From 89e4b219da21cb61f8d799ee338b647b2035ab67 Mon Sep 17 00:00:00 2001 From: Mochamad Noor Syamsu Date: Wed, 30 Mar 2022 12:18:27 +0800 Subject: [PATCH 1/2] added: configuration to disable advertising --- README.md | 54 +++++++++---------- .../tech/hyperjump/example/MainActivity.kt | 3 +- .../services/BluetoothMonitoringService.kt | 37 ++++++++----- .../hyperjump/hypertrace/HyperTraceSdk.kt | 14 +++-- 4 files changed, 62 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 78eece2..ce0dbed 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Android Hypertrace - Kotlin implementation of OpenTrace by Hyperjump -Kotlin OpenTrace implementation based on [BlueTrace specification](https://bluetrace.io/static/bluetrace_whitepaper-938063656596c104632def383eb33b3c.pdf). +Kotlin OpenTrace implementation based on [BlueTrace specification](https://bluetrace.io/static/bluetrace_whitepaper-938063656596c104632def383eb33b3c.pdf). Example app is available in [example module](https://github.com/hyperjumptech/hypertrace-android-sdk/tree/main/example/src/main). ### Table of Content @@ -66,32 +66,31 @@ HypertraceSdk.startService(config) ##### Available configuration -| Field | Type | Description | Mandatory | Default | -| :--------------------------------- | :------------------- | :------------------------------------------------------------------------------------------------------------------------------ | :-------- | :------------ | -| notificationChannelCreator | Function | Kotlin higher-order function for SDK to create android notification channel. (Required for API level 26 / Android O). | **YES** | - | -| foregroundNotificationCreator | Function | Kotlin higher-order function for SDK to create notification when service is actively running. | **YES** | - | -| bluetoothFailedNotificationCreator | Function | Kotlin higher-order function for SDK to create notification when service fails to access bluetooth and location permissions. | **YES** | - | -| userId | string | Main application's user ID. **Must be** 21 characters. | **YES** | - | -| organization | string | Application's organization name. Typically, this is a combination of `COUNTRY_CODE` and short organization name. | **YES** | - | -| baseUrl | string | URL for [Hypertrace server](https://github.com/hyperjumptech/hypertrace) implementation. **Must end** with slash `/` character. | **YES** | - | -| bleServiceUuid | string | BLE service UUID. **Must be** a valid UUID. | **YES** | - | -| bleCharacteristicUuid | string | BLE characteristic UUID. **Must be** a valid UUID. | **YES** | - | -| debug | boolean | Enable showing street pass list and bluetooth scanning activity | **NO** | - | -| keepAliveService | boolean | If `true`, Hypertrace will try to restart service everytime it is killed. | **NO** | `false` | -| scanDuration | long | Duration of each bluetooth scan action in **miliseconds.** Default to 10 seconds. | **NO** | 10_000 | -| minScanInterval | long | Minimum scan interval in **miliseconds.** Randomized between minScanInterval and maxScanInterval. Default to 30 seconds. | **NO** | 30_000 | -| maxScanInterval | long | Maximum scan interval in **miliseconds.** Randomized between minScanInterval and maxScanInterval. Default to 40 seconds. | **NO** | 40_000 | -| advertisingDuration | long | Duration of each bluetooth advertising action in **miliseconds.** Default to 30 minutes. | **NO** | 180_000 | -| advertisingInterval | long | Interval between bluetooth advertising action in **miliseconds.** Default to 6 seconds. | **NO** | 6_000 | -| purgeRecordInterval | long | Interval between purge action of encounter's records in **miliseconds.** Default to 24 hours. | **NO** | 86_400_000 | -| recordTTL | long | The lifetime of encounter's records in **miliseconds.** Default to 21 days. | **NO** | 1_814_400_000 | -| maxPeripheralQueueTime | long | Maximum time of a peripheral to wait to be processed in **miliseconds.** Default to 10 seconds. | **NO** | 10_000 | -| deviceConnectionTimeout | long | Maximum time of a peripheral read-write action in **miliseconds.** Default to 6 seconds. | **NO** | 6_000 | -| deviceBlacklistDuration | long | Maximum time of a device to be blacklisted time in **miliseconds.** Default to 1.5 minutes. | **NO** | 90_000 | -| temporaryIdCheckInterval | long | Interval between temporary IDs' supply check **miliseconds.** Default to 10 minutes. | **NO** | 600_000 | -| bluetoothServiceHeartBeat | long | Interval between OpenTrace bluetooth service check **miliseconds.** Default to 15 minutes. | **NO** | 900_000 | -| certificatePinner | CertificatePinner | Helper for certificate pinning provided by OkHttp. See [**Security Enhancements.**](#security-enhancements) | **NO** | null | -| okHttpConfig | OkHttpClient.Builder | For a complete control of SDK's OkHttpClient. | **NO** | null | +| Field | Type | Description | Mandatory | Default | +| :--------------------------------- | :------------------- | :------------------------------------------------------------------------------------------------------------------------------ | :-------- | :--------------------------------------------------------- | +| notificationChannelCreator | Function | Kotlin higher-order function for SDK to create android notification channel. (Required for API level 26 / Android O). | **YES** | - | +| foregroundNotificationCreator | Function | Kotlin higher-order function for SDK to create notification when service is actively running. | **YES** | - | +| bluetoothFailedNotificationCreator | Function | Kotlin higher-order function for SDK to create notification when service fails to access bluetooth and location permissions. | **YES** | - | +| userId | string | Main application's user ID. **Must be** 21 characters. | **YES** | - | +| organization | string | Application's organization name. Typically, this is a combination of `COUNTRY_CODE` and short organization name. | **YES** | - | +| baseUrl | string | URL for [Hypertrace server](https://github.com/hyperjumptech/hypertrace) implementation. **Must end** with slash `/` character. | **YES** | - | +| bleServiceUuid | string | BLE service UUID. **Must be** a valid UUID. | **YES** | - | +| bleCharacteristicUuid | string | BLE characteristic UUID. **Must be** a valid UUID. | **YES** | - | +| debug | boolean | Enable showing street pass list and bluetooth scanning activity | **NO** | - | +| keepAliveService | boolean | If `true`, Hypertrace will try to restart service everytime it is killed. | **NO** | `false` | +| scanDuration | long | Duration of each bluetooth scan action in **miliseconds.** Default to 10 seconds. | **NO** | 10_000 | +| minScanInterval | long | Minimum scan interval in **miliseconds.** Randomized between minScanInterval and maxScanInterval. Default to 30 seconds. | **NO** | 30_000 | +| maxScanInterval | long | Maximum scan interval in **miliseconds.** Randomized between minScanInterval and maxScanInterval. Default to 40 seconds. | **NO** | 40_000 | +| advertising | Config.Advertising | Hypertrace configuration for advertising's duration and interval. Default to `Advertising.Enable` | **NO** | `Advertising.Enable(duration = 180_000, interval = 6_000)` | +| purgeRecordInterval | long | Interval between purge action of encounter's records in **miliseconds.** Default to 24 hours. | **NO** | 86_400_000 | +| recordTTL | long | The lifetime of encounter's records in **miliseconds.** Default to 21 days. | **NO** | 1_814_400_000 | +| maxPeripheralQueueTime | long | Maximum time of a peripheral to wait to be processed in **miliseconds.** Default to 10 seconds. | **NO** | 10_000 | +| deviceConnectionTimeout | long | Maximum time of a peripheral read-write action in **miliseconds.** Default to 6 seconds. | **NO** | 6_000 | +| deviceBlacklistDuration | long | Maximum time of a device to be blacklisted time in **miliseconds.** Default to 1.5 minutes. | **NO** | 90_000 | +| temporaryIdCheckInterval | long | Interval between temporary IDs' supply check **miliseconds.** Default to 10 minutes. | **NO** | 600_000 | +| bluetoothServiceHeartBeat | long | Interval between OpenTrace bluetooth service check **miliseconds.** Default to 15 minutes. | **NO** | 900_000 | +| certificatePinner | CertificatePinner | Helper for certificate pinning provided by OkHttp. See [**Security Enhancements.**](#security-enhancements) | **NO** | null | +| okHttpConfig | OkHttpClient.Builder | For a complete control of SDK's OkHttpClient. | **NO** | null | #### Stop background service @@ -185,4 +184,3 @@ For more information visit [https://android-developers.googleblog.com/2020/04/go **0.9.0** - First release. - diff --git a/example/src/main/java/tech/hyperjump/example/MainActivity.kt b/example/src/main/java/tech/hyperjump/example/MainActivity.kt index d8aa8dc..f4bbe4a 100644 --- a/example/src/main/java/tech/hyperjump/example/MainActivity.kt +++ b/example/src/main/java/tech/hyperjump/example/MainActivity.kt @@ -16,11 +16,11 @@ import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.lifecycle.lifecycleScope +import io.bluetrace.opentrace.streetpassdebug.StreetPassDebugActivity import kotlinx.android.synthetic.main.activity_main.* import pub.devrel.easypermissions.EasyPermissions import tech.hyperjump.hypertrace.HyperTraceSdk import tech.hyperjump.hypertrace.scandebug.ScanDebugActivity -import io.bluetrace.opentrace.streetpassdebug.StreetPassDebugActivity import java.security.SecureRandom import java.security.cert.X509Certificate import javax.net.ssl.SSLContext @@ -121,6 +121,7 @@ class MainActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks { } private fun buildConfig(): HyperTraceSdk.Config { + // hypertrace server requires uid to be 21 character length userId = generateUserId(21) // FIXME change to hypertrace server implementation val baseUrl = "https://192.108.0.0/" diff --git a/hypertrace/src/main/java/io/bluetrace/opentrace/services/BluetoothMonitoringService.kt b/hypertrace/src/main/java/io/bluetrace/opentrace/services/BluetoothMonitoringService.kt index b1ec3f8..c45ecf3 100644 --- a/hypertrace/src/main/java/io/bluetrace/opentrace/services/BluetoothMonitoringService.kt +++ b/hypertrace/src/main/java/io/bluetrace/opentrace/services/BluetoothMonitoringService.kt @@ -21,12 +21,6 @@ import io.bluetrace.opentrace.bluetooth.gatt.STREET_PASS import io.bluetrace.opentrace.idmanager.TempIDManager import io.bluetrace.opentrace.idmanager.TemporaryID import io.bluetrace.opentrace.logging.CentralLog -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch -import pub.devrel.easypermissions.EasyPermissions -import tech.hyperjump.hypertrace.* import io.bluetrace.opentrace.status.Status import io.bluetrace.opentrace.status.persistence.StatusRecord import io.bluetrace.opentrace.status.persistence.StatusRecordStorage @@ -36,6 +30,14 @@ import io.bluetrace.opentrace.streetpass.StreetPassServer import io.bluetrace.opentrace.streetpass.StreetPassWorker import io.bluetrace.opentrace.streetpass.persistence.StreetPassRecord import io.bluetrace.opentrace.streetpass.persistence.StreetPassRecordStorage +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import pub.devrel.easypermissions.EasyPermissions +import tech.hyperjump.hypertrace.BuildConfig +import tech.hyperjump.hypertrace.HyperTraceSdk +import tech.hyperjump.hypertrace.R import java.lang.ref.WeakReference import kotlin.coroutines.CoroutineContext @@ -325,7 +327,10 @@ class BluetoothMonitoringService : Service(), CoroutineScope { private fun actionAdvertise() { setupAdvertiser() if (isBluetoothEnabled()) { - advertiser?.startAdvertising(advertisingDuration) + val duration = HyperTraceSdk.CONFIG.advertising.let { + if (it is HyperTraceSdk.Config.Advertising.Enable) it.duration else 0 + } + advertiser?.startAdvertising(duration) } else { CentralLog.w(TAG, "Unable to start advertising, bluetooth is off") } @@ -357,6 +362,8 @@ class BluetoothMonitoringService : Service(), CoroutineScope { } private fun setupAdvertisingCycles() { + // ignore if disabled + if (HyperTraceSdk.CONFIG.advertising is HyperTraceSdk.Config.Advertising.Disable) return commandHandler.scheduleNextAdvertise(0) } @@ -377,8 +384,12 @@ class BluetoothMonitoringService : Service(), CoroutineScope { } private fun scheduleAdvertisement() { - if (!infiniteAdvertising) { - commandHandler.scheduleNextAdvertise(advertisingDuration + advertisingGap) + // ignore if disabled + if (HyperTraceSdk.CONFIG.advertising is HyperTraceSdk.Config.Advertising.Disable) return + val advertisingConfig = HyperTraceSdk.CONFIG.advertising + if (!infiniteAdvertising && advertisingConfig is HyperTraceSdk.Config.Advertising.Enable) { + val delay = advertisingConfig.duration + advertisingConfig.interval + commandHandler.scheduleNextAdvertise(delay) } } @@ -429,6 +440,8 @@ class BluetoothMonitoringService : Service(), CoroutineScope { } if (!infiniteAdvertising) { + // ignore if disabled + if (HyperTraceSdk.CONFIG.advertising is HyperTraceSdk.Config.Advertising.Disable) return if (!commandHandler.hasAdvertiseScheduled()) { CentralLog.w(TAG, "Missing Advertise Schedule - rectifying") // setupAdvertisingCycles() @@ -637,14 +650,10 @@ class BluetoothMonitoringService : Service(), CoroutineScope { var broadcastMessage: TemporaryID? = null - //should be more than advertising gap? + //should be more than advertising interval val scanDuration: Long = HyperTraceSdk.CONFIG.scanDuration val minScanInterval: Long = HyperTraceSdk.CONFIG.minScanInterval val maxScanInterval: Long = HyperTraceSdk.CONFIG.maxScanInterval - - val advertisingDuration: Long = HyperTraceSdk.CONFIG.advertisingDuration - val advertisingGap: Long = HyperTraceSdk.CONFIG.advertisingInterval - val maxQueueTime: Long = HyperTraceSdk.CONFIG.maxPeripheralQueueTime val bmCheckInterval: Long = HyperTraceSdk.CONFIG.temporaryIdCheckInterval val healthCheckInterval: Long = HyperTraceSdk.CONFIG.bluetoothServiceHeartBeat diff --git a/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt b/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt index 43e2d1c..cc8679d 100644 --- a/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt +++ b/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt @@ -131,8 +131,10 @@ object HyperTraceSdk { val scanDuration: Long = 10_000, val minScanInterval: Long = 30_000, val maxScanInterval: Long = 40_000, - val advertisingDuration: Long = 180_000, // 30 minutes - val advertisingInterval: Long = 6_000, + val advertising: Advertising = Advertising.Enable( + duration = 180_000, // 30 minutes + interval = 6_000, + ), val purgeRecordInterval: Long = 86_400_000, // 24 hours val recordTTL: Long = 1_814_400_000, // 21 days val maxPeripheralQueueTime: Long = 10_000, @@ -144,8 +146,14 @@ object HyperTraceSdk { val okHttpConfig: (OkHttpClient.Builder.() -> Unit)? = null ) { + sealed class Advertising { + + object Disable : Advertising() + + class Enable(val duration: Long, val interval: Long) : Advertising() + } + fun validateConfig() { - if (userId.length < 21) throw Exception("User ID must have exactly 21 characters.") if (organization.isEmpty()) throw Exception("Organization Code cannot be empty.") if (baseUrl.isEmpty()) throw Exception("Base URL cannot be empty.") if (baseUrl.last() != '/') throw Exception("Base URL must end with slash '/'.") From 2f6ea567c01d1efc14168944bf7d1c8e1dc28539 Mon Sep 17 00:00:00 2001 From: Mochamad Noor Syamsu Date: Wed, 30 Mar 2022 12:35:10 +0800 Subject: [PATCH 2/2] prevent disable and enable unminified --- .../src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt b/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt index cc8679d..9ba6749 100644 --- a/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt +++ b/hypertrace/src/main/java/tech/hyperjump/hypertrace/HyperTraceSdk.kt @@ -148,8 +148,10 @@ object HyperTraceSdk { sealed class Advertising { + @Keep object Disable : Advertising() + @Keep class Enable(val duration: Long, val interval: Long) : Advertising() }