MainApplication.kt

We set these initializations here instead of in an Activity in order to accommodate an app with a background service for the scanning. If you need only a foreground activity, you can simply host them in the onCreate() of a main activity.
package my.package

import android.app.Application
import my.package.ble.ScannerManager

class MainApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        // delegated to a ble component, to keep the pure app module clean of direct accesses to the library
        ScannerManager.init(this)
    }
}

MainActivity.kt

How screens and layouts are implemented (XML, Jetpack Compose, ...) is out of scope of the samples. An (UI) marker is used in the code comments to denote this point.
package my.package

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import my.package.ble.Configuration
import my.package.ble.IStatusCallback
import my.package.ble.ScannerManager
import my.package.ble.UserConfig

class MainActivity : ComponentActivity() {
    // actions are delegated to a component
    private lateinit var mScannerManager: ScannerManager
    // configuration settings are delegated to a component
    private lateinit var mConfiguration: Configuration
    // a status is kept to know if the scanning is active
    private var mIsScanning: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        if (BuildConfig.DEBUG) Log.d(TAG, "lifecycle onCreate")
        super.onCreate(savedInstanceState)

        mScannerManager = ScannerManager(this)
        // here, a simple interactive configuration, assuming a user in control
        mConfiguration = UserConfig.create()

        // ... (UI) setup your screen layout
        // typically, for this sample, with start and stop buttons to act on the scanning,
        // respectively associated with onClickSetup() and onClickTeardown()
    }

    override fun onDestroy() {
        // should be harmless if already stopped some other way (for example a receiver detecting that the Bluetooth has turned off)
        if (mIsScanning) mScannerManager.tearDown()
        super.onDestroy()
    }

    private val mStatusCallback = object : IStatusCallback {
        override fun onResult(isScanning: Boolean) {
            if (BuildConfig.DEBUG) Log.d(TAG, "onResult: isScanning $isScanning")
            mIsScanning = isScanning
            // ... (UI) may need to update some elements, like button properties (text, enabled, ...)
        }

        override fun onError(message: String) {
            if (BuildConfig.DEBUG) Log.d(TAG, "onError $message")
            // ... (UI) inform of the failure
        }
    }

    private fun onClickSetup() {
        if (BuildConfig.DEBUG) Log.d(TAG, "onClickSetUp")
        if (mScannerManager.isBluetoothDisabled) {
            // ... (UI) inform that the app can't work at all if the Bluetooth is off
        } else {
            if (mScannerManager.isLocationDisabled) {
                // ... (UI) inform that no detection will be accessible until Location is enabled
            }
            // ... (UI) according to RadioButtons, may call mConfiguration.setRangingScanFrequency() (default setting)
            // or mConfiguration.setMonitoringScanFrequency()
            // ... (UI) according to a CheckBox, may set mConfiguration.verbose = true
            mScannerManager.setUp(mConfiguration, mStatusCallback)
        }
    }

    private fun onClickTeardown() {
      if (BuildConfig.DEBUG) Log.d(TAG, "onClickTearDown")
        mScannerManager.tearDown(mStatusCallback)
    }

    private companion object {
        private val TAG = MainActivity::class.java.simpleName
    }
}

IStatusCallback.kt

package my.package.ble

interface IStatusCallback {
    fun onResult(isScanning: Boolean)
    fun onError(message: String)
}