# MainActivity

## Overview

The `MainActivity` serves as the entry point for the MultiSet SDK demo application. It demonstrates SDK initialization, authentication handling, and navigation to the AR localization activity.

## Description

This activity is responsible for:

1. Initializing the MultiSet SDK with credentials
2. Handling the authentication flow
3. Managing camera and ARCore permissions
4. Launching the unified `MultiSetLocalizationActivity` for single-frame or multi-frame localization
5. Launching `ObjectTrackingActivity` for AR object detection and tracking

The landing page uses a card-based layout:

* **Auth Button** — full-width, shows authentication state
* **Localization Card** — displays map code, a mode toggle (Single Frame / Multi Frame), and a Start Localization button
* **Object Tracking Card** — displays configured object codes and a Start Object Tracking button

***

## Authentication Flow

### 1. SDK Initialization

The SDK is initialized using credentials from `BuildConfig`:

```kotlin
val config = MultiSetConfig.Builder(clientId, clientSecret)
    .mapCode(mapCode)           // or .mapSetCode(mapSetCode)
    .enableMeshVisualization(true)
    .backgroundLocalization(true)
    .build()

MultiSetSDK.initialize(this, config, this)
```

### 2. Configuration Builder Options

| Method                             | Description                                             |
| ---------------------------------- | ------------------------------------------------------- |
| `mapCode(String)`                  | Set a single map code for localization                  |
| `mapSetCode(String)`               | Set a map set code for localizing against multiple maps |
| `enableMeshVisualization(Boolean)` | Enable/disable 3D mesh overlay visualization            |
| `backgroundLocalization(Boolean)`  | Enable/disable background localization                  |

### 3. Authentication Callbacks

The activity implements `MultiSetCallback` to receive authentication events:

```kotlin
override fun onSDKReady() {
    // SDK is initialized, authentication in progress
}

override fun onAuthenticationSuccess() {
    // Authentication successful, ready for localization
    // Enable localization buttons
}

override fun onAuthenticationFailure(error: String) {
    // Authentication failed
    // Show error message and enable retry
}
```

***

## APIs Used for Authentication

### MultiSetSDK

| Method                                              | Description                                               |
| --------------------------------------------------- | --------------------------------------------------------- |
| `MultiSetSDK.initialize(context, config, callback)` | Initializes the SDK with configuration and callback       |
| `MultiSetSDK.getLastLocalizationResult()`           | Returns the last successful `LocalizationResult`, or null |

### MultiSetConfig.Builder

| Method                             | Parameters       | Description                                      |
| ---------------------------------- | ---------------- | ------------------------------------------------ |
| `Builder(clientId, clientSecret)`  | `String, String` | Creates a configuration builder with credentials |
| `mapCode(code)`                    | `String`         | Sets the map code for single-map localization    |
| `mapSetCode(code)`                 | `String`         | Sets the map set code for multi-map localization |
| `enableMeshVisualization(enabled)` | `Boolean`        | Enables mesh visualization after localization    |
| `backgroundLocalization(enabled)`  | `Boolean`        | Enables background localization                  |
| `build()`                          | -                | Builds the configuration object                  |

***

## Public Methods

### setupUI()

Initializes the UI components and sets up button click listeners:

* Authentication button (retry on failure)
* Mode toggle group (Single Frame / Multi Frame selection)
* Start Localization button
* Start Object Tracking button

### initializeSDK()

Initializes the MultiSet SDK with credentials from `BuildConfig`:

* Validates that `clientId` and `clientSecret` are configured
* Validates that either `mapCode` or `mapSetCode` is configured
* Builds the SDK configuration
* Calls `MultiSetSDK.initialize()`

### checkCameraPermission()

Checks and requests camera permission using the Android Activity Result API.

**Returns:** `Boolean` - `true` if permission is already granted, `false` if permission request was launched.

### checkARCoreAndProceed()

Checks ARCore availability and installation status:

* If ARCore is installed, proceeds to start AR session
* If ARCore needs installation, requests installation
* If ARCore is not supported, shows error message

### startARSession()

Launches either `MultiSetLocalizationActivity` or `ObjectTrackingActivity` based on the pending action:

```kotlin
// Localization
val intent = Intent(this, MultiSetLocalizationActivity::class.java)
intent.putExtra(
    MultiSetLocalizationActivity.EXTRA_LOCALIZATION_MODE,
    (pendingLocalizationType ?: LocalizationMode.MULTI_FRAME).name
)
startActivity(intent)

// Object Tracking
val intent = Intent(this, ObjectTrackingActivity::class.java)
intent.putExtra(ObjectTrackingActivity.EXTRA_OBJECT_CODES, objectCodes)
startActivity(intent)
```

***

## Callbacks (MultiSetCallback Interface)

### onSDKReady()

Called when the SDK has been initialized and is beginning authentication.

```kotlin
override fun onSDKReady() {
    runOnUiThread {
        binding.authButton.text = getString(R.string.authenticating)
    }
}
```

### onAuthenticationSuccess()

Called when authentication with the MultiSet backend is successful. Enables the Localization and Object Tracking buttons and updates the auth button to show a green "Authenticated" state.

```kotlin
override fun onAuthenticationSuccess() {
    runOnUiThread {
        binding.authButton.text = getString(R.string.authenticated)
        binding.authButton.isEnabled = false
        binding.authButton.backgroundTintList = ColorStateList.valueOf(
            ContextCompat.getColor(this, R.color.success)
        )
        binding.localizationButton.isEnabled = true
        binding.objectTrackingButton.isEnabled = true
    }
}
```

### onAuthenticationFailure(error: String)

Called when authentication fails.

| Parameter | Type     | Description                                 |
| --------- | -------- | ------------------------------------------- |
| `error`   | `String` | Error message describing the failure reason |

```kotlin
override fun onAuthenticationFailure(error: String) {
    runOnUiThread {
        binding.statusText.text = "Authentication Failed"
        binding.authButton.isEnabled = true
        showToast("Authentication failed: $error")
    }
}
```

### onLocalizationSuccess(result: LocalizationResult)

Called when localization succeeds. The result can be logged or used by the host application.

| Parameter | Type                 | Description                                                                                     |
| --------- | -------------------- | ----------------------------------------------------------------------------------------------- |
| `result`  | `LocalizationResult` | Contains map code, map codes list, position, rotation, confidence, and optional geo-coordinates |

```kotlin
override fun onLocalizationSuccess(result: LocalizationResult) {
    Log.d(TAG, "Localization success - mapCode: ${result.mapCode}, " +
            "mapCodes: ${result.mapCodes}, " +
            "position: [${result.position.joinToString()}], " +
            "rotation: [${result.rotation.joinToString()}], " +
            "confidence: ${result.confidence}")
}
```

### onLocalizationFailure(error: String)

Called when localization fails. In `MainActivity`, this is handled by the AR activity.

| Parameter | Type     | Description                                 |
| --------- | -------- | ------------------------------------------- |
| `error`   | `String` | Error message describing the failure reason |

### onTrackingStateChanged(state: TrackingState)

Called when AR tracking state changes. Handled internally by the AR activities.

| Parameter | Type            | Description                                        |
| --------- | --------------- | -------------------------------------------------- |
| `state`   | `TrackingState` | Current tracking state (TRACKING, PAUSED, STOPPED) |

### onObjectTrackingSuccess(result: ObjectTrackingResult)

Called when an object is successfully tracked. Forwarded from `ObjectTrackingActivity` via `MultiSetSDK.getCallback()`.

| Parameter | Type                   | Description                                     |
| --------- | ---------------------- | ----------------------------------------------- |
| `result`  | `ObjectTrackingResult` | Contains object code, pose data, and confidence |

```kotlin
override fun onObjectTrackingSuccess(result: ObjectTrackingResult) {
    Log.d(TAG, "Object tracking success - objectCode: ${result.objectCode}, " +
            "position: [${result.position.joinToString()}], " +
            "confidence: ${result.confidence}")
}
```

### onObjectTrackingFailure(error: String)

Called when object tracking fails.

| Parameter | Type     | Description                                 |
| --------- | -------- | ------------------------------------------- |
| `error`   | `String` | Error message describing the failure reason |

```kotlin
override fun onObjectTrackingFailure(error: String) {
    Log.d(TAG, "Object tracking failure: $error")
}
```

***

## LocalizationResult

| Property         | Type              | Description                                      |
| ---------------- | ----------------- | ------------------------------------------------ |
| `mapCode`        | `String`          | The code of the map where localization succeeded |
| `mapCodes`       | `List<String>`    | All map codes returned by the localization API   |
| `position`       | `FloatArray`      | XYZ position coordinates                         |
| `rotation`       | `FloatArray`      | XYZW quaternion rotation                         |
| `confidence`     | `Float?`          | Confidence score of the localization (0.0 - 1.0) |
| `geoCoordinates` | `GeoCoordinates?` | Optional geographic coordinates                  |

***

## TrackingState

| Value      | Description                       |
| ---------- | --------------------------------- |
| `TRACKING` | AR tracking is working normally   |
| `PAUSED`   | AR tracking is temporarily paused |
| `STOPPED`  | AR tracking has stopped           |

***

## Usage Example

```kotlin
class MainActivity : AppCompatActivity(), MultiSetCallback {

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

        // Initialize SDK
        val config = MultiSetConfig.Builder(
            BuildConfig.MULTISET_CLIENT_ID,
            BuildConfig.MULTISET_CLIENT_SECRET
        )
        .mapCode(BuildConfig.MULTISET_MAP_CODE)
        .enableMeshVisualization(true)
        .backgroundLocalization(true)
        .build()

        MultiSetSDK.initialize(this, config, this)
    }

    override fun onAuthenticationSuccess() {
        // Enable localization and object tracking buttons in the UI
    }

    // Launch localization
    fun launchLocalization(mode: LocalizationMode) {
        val intent = Intent(this, MultiSetLocalizationActivity::class.java)
        intent.putExtra(MultiSetLocalizationActivity.EXTRA_LOCALIZATION_MODE, mode.name)
        startActivity(intent)
    }

    // Launch object tracking
    fun launchObjectTracking() {
        val objectCodes = BuildConfig.MULTISET_OBJECT_CODES
            .split(",").map { it.trim() }.filter { it.isNotEmpty() }.toTypedArray()

        ObjectTrackingConfig.objectCodes = objectCodes
        ObjectTrackingConfig.validate()

        val intent = Intent(this, ObjectTrackingActivity::class.java)
        intent.putExtra(ObjectTrackingActivity.EXTRA_OBJECT_CODES, objectCodes)
        startActivity(intent)
    }

    override fun onLocalizationSuccess(result: LocalizationResult) {
        Log.d("MainActivity", "Localized at mapCode: ${result.mapCode}")
    }

    override fun onObjectTrackingSuccess(result: ObjectTrackingResult) {
        Log.d("MainActivity", "Tracked object: ${result.objectCode}")
    }

    override fun onObjectTrackingFailure(error: String) {
        Log.e("MainActivity", "Tracking failed: $error")
    }

    override fun onAuthenticationFailure(error: String) {
        Toast.makeText(this, "Auth failed: $error", Toast.LENGTH_SHORT).show()
    }

    // ... other callback implementations
}
```

***

## Related

* [MultiSetLocalizationActivity](https://docs.multiset.ai/native-support/android-native/sample-activities/multisetlocalizationactivity)
* [ObjectTrackingActivity](https://docs.multiset.ai/native-support/android-native/sample-activities/objecttrackingactivity)
* [LocalizationConfig](https://docs.multiset.ai/native-support/android-native/api-reference/localizationconfig)
* [ObjectTrackingConfig](https://docs.multiset.ai/native-support/android-native/api-reference/objecttrackingconfig)
