diff --git a/example/src/main/java/io/radar/example/MainActivity.kt b/example/src/main/java/io/radar/example/MainActivity.kt index df01b6c21..880890ee6 100644 --- a/example/src/main/java/io/radar/example/MainActivity.kt +++ b/example/src/main/java/io/radar/example/MainActivity.kt @@ -14,6 +14,7 @@ import io.radar.sdk.RadarVerifiedReceiver import io.radar.sdk.model.RadarVerifiedLocationToken import org.json.JSONObject import java.util.EnumSet +import androidx.core.content.edit class MainActivity : AppCompatActivity() { diff --git a/sdk/build.gradle b/sdk/build.gradle index faa9bb9cd..7e059f5cb 100644 --- a/sdk/build.gradle +++ b/sdk/build.gradle @@ -10,7 +10,7 @@ apply plugin: "org.jetbrains.dokka" apply plugin: 'io.radar.mvnpublish' ext { - radarVersion = '3.15.0' + radarVersion = '3.16.0' } String buildNumber = ".${System.currentTimeMillis()}" diff --git a/sdk/src/main/java/io/radar/sdk/Radar.kt b/sdk/src/main/java/io/radar/sdk/Radar.kt index 209e888b9..66b2653ed 100644 --- a/sdk/src/main/java/io/radar/sdk/Radar.kt +++ b/sdk/src/main/java/io/radar/sdk/Radar.kt @@ -8,6 +8,7 @@ import android.location.Location import android.os.Build import android.os.Handler import androidx.annotation.RequiresApi +import androidx.core.content.edit import io.radar.sdk.model.* import io.radar.sdk.model.RadarEvent.RadarEventVerification import io.radar.sdk.util.RadarLogBuffer @@ -463,7 +464,12 @@ object Radar { * @param[fraud] A boolean indicating whether to enable additional fraud detection signals for location verification. */ @JvmStatic - fun initialize(context: Context?, publishableKey: String? = null, receiver: RadarReceiver? = null, provider: RadarLocationServicesProvider = RadarLocationServicesProvider.GOOGLE, fraud: Boolean = false) { + fun initialize( + context: Context?, + publishableKey: String? = null, + receiver: RadarReceiver? = null, + provider: RadarLocationServicesProvider = RadarLocationServicesProvider.GOOGLE, + fraud: Boolean = false) { if (context == null) { return } @@ -534,16 +540,26 @@ object Radar { } application?.registerActivityLifecycleCallbacks(RadarActivityLifecycleCallbacks(fraud)) - val featureSettings = RadarSettings.getFeatureSettings(this.context) - if (featureSettings.usePersistence) { + val sdkConfiguration = RadarSettings.getSdkConfiguration(this.context) + if (sdkConfiguration.usePersistence) { Radar.loadReplayBufferFromSharedPreferences() } val usage = "initialize" this.apiClient.getConfig(usage, false, object : RadarApiClient.RadarGetConfigApiCallback { override fun onComplete(status: RadarStatus, config: RadarConfig) { - locationManager.updateTrackingFromMeta(config?.meta) - RadarSettings.setFeatureSettings(context, config?.meta.featureSettings) + if (status == RadarStatus.SUCCESS) { + locationManager.updateTrackingFromMeta(config.meta) + RadarSettings.setSdkConfiguration(context, config.meta.sdkConfiguration) + } + + val sdkConfiguration = RadarSettings.getSdkConfiguration(context) + if (sdkConfiguration.startTrackingOnInitialize && !RadarSettings.getTracking(context)) { + Radar.startTracking(Radar.getTrackingOptions()) + } + if (sdkConfiguration.trackOnceOnAppOpen) { + Radar.trackOnce() + } } }) @@ -3113,8 +3129,18 @@ object Radar { if (!initialized) { return } - - RadarSettings.setLogLevel(context, level) + // update clientSdkConfiguration if the new level is different, otherwise no-op + val sdkConfiguration = RadarSettings.getClientSdkConfiguration(context) + if (sdkConfiguration.optString("logLevel") == level.toString().lowercase()) { + return; + } + sdkConfiguration.put("logLevel", level.toString().lowercase()) + RadarSettings.setClientSdkConfiguration(context, sdkConfiguration) + // if the current log level is already the target log level, no-op + if (RadarSettings.getLogLevel(context) == level) { + return; + } + RadarSdkConfiguration.updateSdkConfigurationFromServer(context) } /** diff --git a/sdk/src/main/java/io/radar/sdk/RadarActivityLifecycleCallbacks.kt b/sdk/src/main/java/io/radar/sdk/RadarActivityLifecycleCallbacks.kt index 838156de8..a8f8da95e 100644 --- a/sdk/src/main/java/io/radar/sdk/RadarActivityLifecycleCallbacks.kt +++ b/sdk/src/main/java/io/radar/sdk/RadarActivityLifecycleCallbacks.kt @@ -20,6 +20,7 @@ internal class RadarActivityLifecycleCallbacks( private val fraud: Boolean = false ) : Application.ActivityLifecycleCallbacks { private var count = 0 + private var isFirstOnResume = true companion object { var foreground: Boolean = false @@ -44,23 +45,36 @@ internal class RadarActivityLifecycleCallbacks( } override fun onActivityResumed(activity: Activity) { - if (count == 0) { + if (count == 0 && !isFirstOnResume) { try { val updated = RadarSettings.updateSessionId(activity.applicationContext) if (updated) { val usage = "resume" Radar.apiClient.getConfig(usage, false, object : RadarApiClient.RadarGetConfigApiCallback { override fun onComplete(status: Radar.RadarStatus, config: RadarConfig) { - Radar.locationManager.updateTrackingFromMeta(config.meta) - RadarSettings.setFeatureSettings(activity.applicationContext, config.meta.featureSettings) + if (status == Radar.RadarStatus.SUCCESS) { + Radar.locationManager.updateTrackingFromMeta(config.meta) + RadarSettings.setSdkConfiguration(activity.applicationContext, config.meta.sdkConfiguration) + } + + val sdkConfiguration = RadarSettings.getSdkConfiguration(activity.applicationContext) + if (sdkConfiguration.trackOnceOnAppOpen) { + Radar.trackOnce() + } } }) + } else { + val sdkConfiguration = RadarSettings.getSdkConfiguration(activity.applicationContext) + if (sdkConfiguration.trackOnceOnAppOpen) { + Radar.trackOnce() + } } } catch (e: Exception) { Log.e(TAG, e.message, e) } } count++ + isFirstOnResume = false foreground = count > 0 Radar.logOpenedAppConversion() @@ -113,6 +127,7 @@ internal class RadarActivityLifecycleCallbacks( } override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + Log.w(TAG, "ON CREATE ${count}") updatePermissionsDenied(activity) } } \ No newline at end of file diff --git a/sdk/src/main/java/io/radar/sdk/RadarApiClient.kt b/sdk/src/main/java/io/radar/sdk/RadarApiClient.kt index 97a100099..55770bb23 100644 --- a/sdk/src/main/java/io/radar/sdk/RadarApiClient.kt +++ b/sdk/src/main/java/io/radar/sdk/RadarApiClient.kt @@ -14,6 +14,7 @@ import org.json.JSONArray import org.json.JSONException import org.json.JSONObject import java.util.* +import java.net.URLEncoder internal class RadarApiClient( private val context: Context, @@ -130,6 +131,8 @@ internal class RadarApiClient( if (usage != null) { queryParams.append("&usage=${usage}") } + val clientSdkConfiguration = RadarSettings.getClientSdkConfiguration(context).toString() + queryParams.append("&clientSdkConfiguration=${URLEncoder.encode(clientSdkConfiguration, "utf-8")}") val path = "v1/config?${queryParams}" val headers = headers(publishableKey) diff --git a/sdk/src/main/java/io/radar/sdk/RadarBeaconManager.kt b/sdk/src/main/java/io/radar/sdk/RadarBeaconManager.kt index 35f249e09..4939ab81d 100644 --- a/sdk/src/main/java/io/radar/sdk/RadarBeaconManager.kt +++ b/sdk/src/main/java/io/radar/sdk/RadarBeaconManager.kt @@ -69,7 +69,7 @@ internal class RadarBeaconManager( } fun startMonitoringBeacons(beacons: Array) { - if (RadarSettings.getFeatureSettings(context).useRadarModifiedBeacon) { + if (RadarSettings.getSdkConfiguration(context).useRadarModifiedBeacon) { return } @@ -149,7 +149,7 @@ internal class RadarBeaconManager( } fun startMonitoringBeaconUUIDs(beaconUUIDs: Array?, beaconUIDs: Array?) { - if (RadarSettings.getFeatureSettings(context).useRadarModifiedBeacon) { + if (RadarSettings.getSdkConfiguration(context).useRadarModifiedBeacon) { return } @@ -256,7 +256,7 @@ internal class RadarBeaconManager( } fun stopMonitoringBeacons() { - if (RadarSettings.getFeatureSettings(context).useRadarModifiedBeacon) { + if (RadarSettings.getSdkConfiguration(context).useRadarModifiedBeacon) { return } diff --git a/sdk/src/main/java/io/radar/sdk/RadarJobScheduler.kt b/sdk/src/main/java/io/radar/sdk/RadarJobScheduler.kt index 54a59dbfe..1e4c6977c 100644 --- a/sdk/src/main/java/io/radar/sdk/RadarJobScheduler.kt +++ b/sdk/src/main/java/io/radar/sdk/RadarJobScheduler.kt @@ -56,7 +56,7 @@ class RadarJobScheduler : JobService() { val sourceStr = stringForSource(source) - val settings = RadarSettings.getFeatureSettings(context) + val settings = RadarSettings.getSdkConfiguration(context) val jobId = BASE_JOB_ID_LOCATIONS + (numActiveLocationJobs.incrementAndGet() % settings.maxConcurrentJobs) val jobInfo = JobInfo.Builder(jobId, componentName) @@ -95,7 +95,7 @@ class RadarJobScheduler : JobService() { val sourceStr = stringForSource(source) - val settings = RadarSettings.getFeatureSettings(context) + val settings = RadarSettings.getSdkConfiguration(context) val jobId = BASE_JOB_ID_BEACONS + (numActiveBeaconJobs.incrementAndGet() % settings.maxConcurrentJobs) val jobInfo = JobInfo.Builder(jobId, componentName) diff --git a/sdk/src/main/java/io/radar/sdk/RadarLocationManager.kt b/sdk/src/main/java/io/radar/sdk/RadarLocationManager.kt index 12a23ff78..88a4717d0 100644 --- a/sdk/src/main/java/io/radar/sdk/RadarLocationManager.kt +++ b/sdk/src/main/java/io/radar/sdk/RadarLocationManager.kt @@ -118,7 +118,7 @@ internal class RadarLocationManager( this.started = false RadarSettings.setTracking(context, false) this.updateTracking() - val settings = RadarSettings.getFeatureSettings(context) + val settings = RadarSettings.getSdkConfiguration(context) if (settings.extendFlushReplays) { Radar.flushReplays() } diff --git a/sdk/src/main/java/io/radar/sdk/RadarLogger.kt b/sdk/src/main/java/io/radar/sdk/RadarLogger.kt index 903592cc4..bb4474e81 100644 --- a/sdk/src/main/java/io/radar/sdk/RadarLogger.kt +++ b/sdk/src/main/java/io/radar/sdk/RadarLogger.kt @@ -79,7 +79,7 @@ internal class RadarLogger( break } } - } + } } fun getBatteryLevel(): Float { diff --git a/sdk/src/main/java/io/radar/sdk/RadarSettings.kt b/sdk/src/main/java/io/radar/sdk/RadarSettings.kt index ed4390429..98e3909cc 100644 --- a/sdk/src/main/java/io/radar/sdk/RadarSettings.kt +++ b/sdk/src/main/java/io/radar/sdk/RadarSettings.kt @@ -3,12 +3,11 @@ package io.radar.sdk import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit -import io.radar.sdk.model.RadarFeatureSettings +import io.radar.sdk.model.RadarSdkConfiguration import org.json.JSONObject import java.text.DecimalFormat import java.util.* - internal object RadarSettings { private const val KEY_PUBLISHABLE_KEY = "publishable_key" @@ -27,7 +26,8 @@ internal object RadarSettings { private const val KEY_REMOTE_TRACKING_OPTIONS = "remote_tracking_options" private const val KEY_FOREGROUND_SERVICE = "foreground_service" private const val KEY_NOTIFICATION_OPTIONS = "notification_options" - private const val KEY_FEATURE_SETTINGS = "feature_settings" + private const val KEY_CLIENT_SDK_CONFIGURATION = "client_sdk_configuration" + private const val KEY_SDK_CONFIGURATION = "sdk_configuration" private const val KEY_TRIP_OPTIONS = "trip_options" private const val KEY_LOG_LEVEL = "log_level" private const val KEY_HOST = "host" @@ -82,7 +82,7 @@ internal object RadarSettings { val timestampSeconds = System.currentTimeMillis() / 1000 val sessionIdSeconds = getSharedPreferences(context).getLong(KEY_SESSION_ID, 0) - val settings = RadarSettings.getFeatureSettings(context) + val settings = getSdkConfiguration(context) if (settings.extendFlushReplays) { Radar.logger.d("Flushing replays from updateSessionId()") Radar.flushReplays() @@ -293,33 +293,49 @@ internal object RadarSettings { getSharedPreferences(context).edit { putString(KEY_TRIP_OPTIONS, optionsJson) } } - fun setFeatureSettings(context: Context, featureSettings: RadarFeatureSettings) { - Radar.setLogPersistenceFeatureFlag(featureSettings.useLogPersistence) - val optionsJson = featureSettings.toJson().toString() + fun setSdkConfiguration(context: Context, configuration: RadarSdkConfiguration?) { + Radar.logger.d("set SDK Configuration | sdkConfiguration = $configuration") + if (configuration != null) { + Radar.setLogPersistenceFeatureFlag(configuration.useLogPersistence) + setLogLevel(context, configuration.logLevel) + val sdkConfigurationString = configuration.toJson().toString() + getSharedPreferences(context).edit { putString(KEY_SDK_CONFIGURATION, sdkConfigurationString) } + } else { + getSharedPreferences(context).edit { remove(KEY_SDK_CONFIGURATION) } + } + } - getSharedPreferences(context).edit { putString(KEY_FEATURE_SETTINGS, optionsJson) } + fun getSdkConfiguration(context: Context): RadarSdkConfiguration { + val sdkConfigurationString = getSharedPreferences(context).getString(KEY_SDK_CONFIGURATION, null) + val sdkConfigurationJSON = sdkConfigurationString?.let { JSONObject(it) } + return RadarSdkConfiguration.fromJson(sdkConfigurationJSON) } - fun getFeatureSettings(context: Context): RadarFeatureSettings { - val sharedPrefFeatureSettings = getSharedPreferences(context).getString(KEY_FEATURE_SETTINGS, null) - try { - Radar.logger.d("Getting feature settings | featureSettings = $sharedPrefFeatureSettings") - } catch (e: Exception) { + fun getClientSdkConfiguration(context: Context): JSONObject { + val sharedPrefClientSdkConfig = getSharedPreferences(context).getString(KEY_CLIENT_SDK_CONFIGURATION, null); + + return if (sharedPrefClientSdkConfig != null) { + JSONObject(sharedPrefClientSdkConfig) + } else { + JSONObject() + } + } + fun setClientSdkConfiguration(context: Context, sdkConfiguration: JSONObject?) { + val sdkConfigurationString = sdkConfiguration?.toString() + getSharedPreferences(context).edit { + putString(KEY_CLIENT_SDK_CONFIGURATION, sdkConfigurationString) } - val optionsJson = sharedPrefFeatureSettings ?: return RadarFeatureSettings.default() - return RadarFeatureSettings.fromJson(JSONObject(optionsJson)) } internal fun getLogLevel(context: Context): Radar.RadarLogLevel { - val logLevelInt = getSharedPreferences(context).getInt(KEY_LOG_LEVEL, 3) + val logLevelInt = getSharedPreferences(context).getInt(KEY_LOG_LEVEL, Radar.RadarLogLevel.INFO.value) val userDebug = getUserDebug(context) return if (userDebug) Radar.RadarLogLevel.DEBUG else Radar.RadarLogLevel.fromInt(logLevelInt) } internal fun setLogLevel(context: Context, level: Radar.RadarLogLevel) { - val logLevelInt = level.value - getSharedPreferences(context).edit { putInt(KEY_LOG_LEVEL, logLevelInt) } + getSharedPreferences(context).edit { putInt(KEY_LOG_LEVEL, level.value) } } internal fun getHost(context: Context): String { diff --git a/sdk/src/main/java/io/radar/sdk/model/RadarFeatureSettings.kt b/sdk/src/main/java/io/radar/sdk/model/RadarFeatureSettings.kt deleted file mode 100644 index eda8393e9..000000000 --- a/sdk/src/main/java/io/radar/sdk/model/RadarFeatureSettings.kt +++ /dev/null @@ -1,62 +0,0 @@ -package io.radar.sdk.model - -import org.json.JSONObject - -/** - * Represents server-side feature settings. - */ -internal data class RadarFeatureSettings( - val maxConcurrentJobs: Int, - val schedulerRequiresNetwork: Boolean, - val usePersistence: Boolean, - val extendFlushReplays: Boolean, - val useLogPersistence: Boolean, - val useRadarModifiedBeacon: Boolean -) { - companion object { - private const val MAX_CONCURRENT_JOBS = "maxConcurrentJobs" - private const val DEFAULT_MAX_CONCURRENT_JOBS = 1 - private const val USE_PERSISTENCE = "usePersistence" - private const val SCHEDULER_REQUIRES_NETWORK = "networkAny" - private const val EXTEND_FLUSH_REPLAYS = "extendFlushReplays" - private const val USE_LOG_PERSISTENCE = "useLogPersistence" - private const val USE_RADAR_MODIFIED_BEACON = "useRadarModifiedBeacon" - - fun fromJson(json: JSONObject?): RadarFeatureSettings { - return if (json == null) { - default() - } else { - RadarFeatureSettings( - json.optInt(MAX_CONCURRENT_JOBS, DEFAULT_MAX_CONCURRENT_JOBS), - json.optBoolean(SCHEDULER_REQUIRES_NETWORK), - json.optBoolean(USE_PERSISTENCE), - json.optBoolean(EXTEND_FLUSH_REPLAYS), - json.optBoolean(USE_LOG_PERSISTENCE), - json.optBoolean(USE_RADAR_MODIFIED_BEACON) - ) - } - } - - fun default(): RadarFeatureSettings { - return RadarFeatureSettings( - DEFAULT_MAX_CONCURRENT_JOBS, - false, // networkAny - false, // usePersistence - false, // extendFlushReplays - false, // useLogPersistence - false, // useRadarModifiedBeacon - ) - } - } - - fun toJson(): JSONObject { - return JSONObject().apply { - putOpt(MAX_CONCURRENT_JOBS, maxConcurrentJobs) - putOpt(SCHEDULER_REQUIRES_NETWORK, schedulerRequiresNetwork) - putOpt(USE_PERSISTENCE, usePersistence) - putOpt(EXTEND_FLUSH_REPLAYS, extendFlushReplays) - putOpt(USE_LOG_PERSISTENCE, useLogPersistence) - putOpt(USE_RADAR_MODIFIED_BEACON, useRadarModifiedBeacon) - } - } -} diff --git a/sdk/src/main/java/io/radar/sdk/model/RadarMeta.kt b/sdk/src/main/java/io/radar/sdk/model/RadarMeta.kt index b37c55b89..bc3de1fb0 100644 --- a/sdk/src/main/java/io/radar/sdk/model/RadarMeta.kt +++ b/sdk/src/main/java/io/radar/sdk/model/RadarMeta.kt @@ -5,21 +5,24 @@ import org.json.JSONObject internal data class RadarMeta( val remoteTrackingOptions: RadarTrackingOptions?, - val featureSettings: RadarFeatureSettings, + val sdkConfiguration: RadarSdkConfiguration?, ) { companion object { private const val TRACKING_OPTIONS = "trackingOptions" - private const val FEATURE_SETTINGS = "featureSettings" + private const val SDK_CONFIGURATION = "sdkConfiguration" fun fromJson(meta: JSONObject?): RadarMeta { val rawOptions = meta?.optJSONObject(TRACKING_OPTIONS) - val rawFeatureSettings = meta?.optJSONObject(FEATURE_SETTINGS) - - return if (rawOptions == null) { - RadarMeta(null, RadarFeatureSettings.fromJson(rawFeatureSettings)) - } else { - RadarMeta(RadarTrackingOptions.fromJson(rawOptions), RadarFeatureSettings.fromJson(rawFeatureSettings)) + val rawSdkConfiguration = meta?.optJSONObject(SDK_CONFIGURATION) + + var trackingOptions: RadarTrackingOptions? = null + if (rawOptions != null) { + trackingOptions = RadarTrackingOptions.fromJson(rawOptions) } + return RadarMeta( + trackingOptions, + RadarSdkConfiguration.fromJson(rawSdkConfiguration), + ) } } } diff --git a/sdk/src/main/java/io/radar/sdk/model/RadarSdkConfiguration.kt b/sdk/src/main/java/io/radar/sdk/model/RadarSdkConfiguration.kt new file mode 100644 index 000000000..e43be6ad2 --- /dev/null +++ b/sdk/src/main/java/io/radar/sdk/model/RadarSdkConfiguration.kt @@ -0,0 +1,74 @@ +package io.radar.sdk.model + +import android.content.Context +import org.json.JSONObject +import io.radar.sdk.Radar +import io.radar.sdk.RadarApiClient +import io.radar.sdk.RadarSettings + +/** + * Represents server-side configuration settings. + */ +internal data class RadarSdkConfiguration( + val maxConcurrentJobs: Int, + val schedulerRequiresNetwork: Boolean, + val usePersistence: Boolean, + val extendFlushReplays: Boolean, + val useLogPersistence: Boolean, + val useRadarModifiedBeacon: Boolean, + val logLevel: Radar.RadarLogLevel, + val startTrackingOnInitialize: Boolean, + val trackOnceOnAppOpen: Boolean, +) { + companion object { + private const val MAX_CONCURRENT_JOBS = "maxConcurrentJobs" + private const val DEFAULT_MAX_CONCURRENT_JOBS = 1 + private const val USE_PERSISTENCE = "usePersistence" + private const val SCHEDULER_REQUIRES_NETWORK = "networkAny" + private const val EXTEND_FLUSH_REPLAYS = "extendFlushReplays" + private const val USE_LOG_PERSISTENCE = "useLogPersistence" + private const val USE_RADAR_MODIFIED_BEACON = "useRadarModifiedBeacon" + private const val LOG_LEVEL = "logLevel" + private const val START_TRACKING_ON_INITIALIZE = "startTrackingOnInitialize" + private const val TRACK_ONCE_ON_APP_OPEN = "trackOnceOnAppOpen" + + fun fromJson(json: JSONObject?): RadarSdkConfiguration { + // set json as empty object if json is null, which uses fallback values + val config = json ?: JSONObject(); + + return RadarSdkConfiguration( + config.optInt(MAX_CONCURRENT_JOBS, DEFAULT_MAX_CONCURRENT_JOBS), + config.optBoolean(SCHEDULER_REQUIRES_NETWORK, false), + config.optBoolean(USE_PERSISTENCE, false), + config.optBoolean(EXTEND_FLUSH_REPLAYS, false), + config.optBoolean(USE_LOG_PERSISTENCE, false), + config.optBoolean(USE_RADAR_MODIFIED_BEACON, false), + Radar.RadarLogLevel.valueOf(config.optString(LOG_LEVEL, "info").uppercase()), + config.optBoolean(START_TRACKING_ON_INITIALIZE, false), + config.optBoolean(TRACK_ONCE_ON_APP_OPEN, false), + ) + } + + fun updateSdkConfigurationFromServer(context: Context) { + Radar.apiClient.getConfig("sdkConfigUpdate", false, object : RadarApiClient.RadarGetConfigApiCallback { + override fun onComplete(status: Radar.RadarStatus, config: RadarConfig) { + RadarSettings.setSdkConfiguration(context, config.meta.sdkConfiguration) + } + }) + } + } + + fun toJson(): JSONObject { + return JSONObject().apply { + putOpt(SCHEDULER_REQUIRES_NETWORK, schedulerRequiresNetwork) + putOpt(MAX_CONCURRENT_JOBS, maxConcurrentJobs) + putOpt(USE_PERSISTENCE, usePersistence) + putOpt(EXTEND_FLUSH_REPLAYS, extendFlushReplays) + putOpt(USE_LOG_PERSISTENCE, useLogPersistence) + putOpt(USE_RADAR_MODIFIED_BEACON, useRadarModifiedBeacon) + putOpt(LOG_LEVEL, logLevel.toString().lowercase()) + putOpt(START_TRACKING_ON_INITIALIZE, startTrackingOnInitialize) + putOpt(TRACK_ONCE_ON_APP_OPEN, trackOnceOnAppOpen) + } + } +} diff --git a/sdk/src/main/java/io/radar/sdk/util/RadarSimpleLogBuffer.kt b/sdk/src/main/java/io/radar/sdk/util/RadarSimpleLogBuffer.kt index 1f683bc86..92ff2299f 100644 --- a/sdk/src/main/java/io/radar/sdk/util/RadarSimpleLogBuffer.kt +++ b/sdk/src/main/java/io/radar/sdk/util/RadarSimpleLogBuffer.kt @@ -34,7 +34,7 @@ internal class RadarSimpleLogBuffer(override val context: Context): RadarLogBuff private val logBuffer = LinkedBlockingDeque() init { - persistentLogFeatureFlag = RadarSettings.getFeatureSettings(context).useLogPersistence + persistentLogFeatureFlag = RadarSettings.getSdkConfiguration(context).useLogPersistence val file = File(context.filesDir, logFileDir) if (!file.exists()) { file.mkdir() diff --git a/sdk/src/main/java/io/radar/sdk/util/RadarSimpleReplayBuffer.kt b/sdk/src/main/java/io/radar/sdk/util/RadarSimpleReplayBuffer.kt index b56a2b47f..5dce6edf1 100644 --- a/sdk/src/main/java/io/radar/sdk/util/RadarSimpleReplayBuffer.kt +++ b/sdk/src/main/java/io/radar/sdk/util/RadarSimpleReplayBuffer.kt @@ -28,8 +28,8 @@ internal class RadarSimpleReplayBuffer(private val context: Context) : RadarRepl buffer.removeFirst() } buffer.offer(RadarReplay(replayParams)) - val featureSettings = RadarSettings.getFeatureSettings(context) - if (featureSettings.usePersistence) { + val sdkConfiguration = RadarSettings.getSdkConfiguration(context) + if (sdkConfiguration.usePersistence) { // if buffer length is above 50, remove every fifth replay from the persisted buffer if (buffer.size > 50) { val prunedBuffer = buffer.filterIndexed { index, _ -> index % 5 != 0 } diff --git a/sdk/src/test/java/io/radar/sdk/RadarTest.kt b/sdk/src/test/java/io/radar/sdk/RadarTest.kt index be1c5539f..7b91ad8fa 100644 --- a/sdk/src/test/java/io/radar/sdk/RadarTest.kt +++ b/sdk/src/test/java/io/radar/sdk/RadarTest.kt @@ -1547,4 +1547,41 @@ class RadarTest { return tripOptions } + @Test + fun test_Radar_setSdkConfiguration() { + val sdkConfiguration = RadarSdkConfiguration(1, false, false, false, false, false, Radar.RadarLogLevel.WARNING, true, true) + + RadarSettings.setUserDebug(context, false) + RadarSettings.setSdkConfiguration(context, sdkConfiguration) + + assertEquals(Radar.RadarLogLevel.WARNING, RadarSettings.getLogLevel(context)) + + apiHelperMock.mockStatus = Radar.RadarStatus.SUCCESS + apiHelperMock.mockResponse = RadarTestUtils.jsonObjectFromResource("/get_config_response.json") + + val latch = CountDownLatch(1) + + Radar.apiClient.getConfig("sdkConfigUpdate", false, object : RadarApiClient.RadarGetConfigApiCallback { + override fun onComplete(status: Radar.RadarStatus, config: RadarConfig) { + RadarSettings.setSdkConfiguration(context, config.meta.sdkConfiguration) + + assertEquals(RadarSettings.getLogLevel(context), Radar.RadarLogLevel.INFO) + + latch.countDown() + } + }) + + ShadowLooper.runUiThreadTasksIncludingDelayedTasks() + latch.await(LATCH_TIMEOUT, TimeUnit.SECONDS) + + Radar.setLogLevel(Radar.RadarLogLevel.DEBUG) + val clientSdkConfiguration = RadarSettings.getClientSdkConfiguration(context) + val logLevel = Radar.RadarLogLevel.valueOf(clientSdkConfiguration.get("logLevel").toString().uppercase()) + assertEquals(Radar.RadarLogLevel.DEBUG, logLevel) + + val savedSdkConfiguration = RadarSettings.getSdkConfiguration(context) + assertEquals(Radar.RadarLogLevel.INFO, savedSdkConfiguration?.logLevel) + assertEquals(true, savedSdkConfiguration?.startTrackingOnInitialize) + assertEquals(true, savedSdkConfiguration?.trackOnceOnAppOpen) + } } diff --git a/sdk/src/test/java/io/radar/sdk/model/RadarFeatureSettingsTest.kt b/sdk/src/test/java/io/radar/sdk/model/RadarSdkConfigurationTest.kt similarity index 65% rename from sdk/src/test/java/io/radar/sdk/model/RadarFeatureSettingsTest.kt rename to sdk/src/test/java/io/radar/sdk/model/RadarSdkConfigurationTest.kt index 417bb2d32..f2e3facfd 100644 --- a/sdk/src/test/java/io/radar/sdk/model/RadarFeatureSettingsTest.kt +++ b/sdk/src/test/java/io/radar/sdk/model/RadarSdkConfigurationTest.kt @@ -1,5 +1,6 @@ package io.radar.sdk.model +import io.radar.sdk.Radar import org.json.JSONObject import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -13,7 +14,7 @@ import kotlin.random.Random * Unit test [RadarFeatureSettings] */ @RunWith(JUnit4::class) -class RadarFeatureSettingsTest { +class RadarSdkConfigurationTest { private var maxConcurrentJobs = -1 private var requiresNetwork = false @@ -22,6 +23,9 @@ class RadarFeatureSettingsTest { private var useLogPersistence = true private var useRadarModifiedBeacon = false private lateinit var jsonString: String + private var logLevel = Radar.RadarLogLevel.INFO + private var startTrackingOnInitialize = false + private var trackOnceOnAppOpen = false @Before fun setUp() { @@ -34,45 +38,57 @@ class RadarFeatureSettingsTest { "usePersistence":$usePersistence, "useRadarModifiedBeacon":$useRadarModifiedBeacon, "useLogPersistence":$useLogPersistence, - "extendFlushReplays":$extendFlushReplays + "extendFlushReplays":$extendFlushReplays, + "logLevel":"info", + "startTrackingOnInitialize":$startTrackingOnInitialize, + "trackOnceOnAppOpen":$trackOnceOnAppOpen }""".trimIndent() } @Test fun testToJson() { assertEquals( - jsonString.removeWhitespace(), - RadarFeatureSettings( + JSONObject(jsonString).toString(), + RadarSdkConfiguration( maxConcurrentJobs, requiresNetwork, usePersistence, extendFlushReplays, useLogPersistence, - useRadarModifiedBeacon - ).toJson().toString().removeWhitespace() + useRadarModifiedBeacon, + logLevel, + startTrackingOnInitialize, + trackOnceOnAppOpen, + ).toJson().toString() ) } @Test fun testFromJson() { - val settings = RadarFeatureSettings.fromJson(JSONObject(jsonString)) + val settings = RadarSdkConfiguration.fromJson(JSONObject(jsonString)) assertEquals(maxConcurrentJobs, settings.maxConcurrentJobs) assertEquals(requiresNetwork, settings.schedulerRequiresNetwork) assertEquals(usePersistence, settings.usePersistence) assertEquals(extendFlushReplays, settings.extendFlushReplays) assertEquals(useLogPersistence, settings.useLogPersistence) assertEquals(useRadarModifiedBeacon, settings.useRadarModifiedBeacon) + assertEquals(logLevel, settings.logLevel) + assertEquals(startTrackingOnInitialize, settings.startTrackingOnInitialize) + assertEquals(trackOnceOnAppOpen, settings.trackOnceOnAppOpen) } @Test fun testDefault() { - val settings = RadarFeatureSettings.default() + val settings = RadarSdkConfiguration.fromJson(null) assertEquals(1, settings.maxConcurrentJobs) assertFalse(settings.schedulerRequiresNetwork) assertFalse(settings.usePersistence) assertFalse(settings.extendFlushReplays) assertFalse(settings.useLogPersistence) assertFalse(settings.useRadarModifiedBeacon) + assertEquals(Radar.RadarLogLevel.INFO, settings.logLevel) + assertFalse(settings.startTrackingOnInitialize) + assertFalse(settings.trackOnceOnAppOpen) } private fun String.removeWhitespace(): String = replace("\\s".toRegex(), "") diff --git a/sdk/src/test/resources/get_config_response.json b/sdk/src/test/resources/get_config_response.json new file mode 100644 index 000000000..aa0299ac0 --- /dev/null +++ b/sdk/src/test/resources/get_config_response.json @@ -0,0 +1,17 @@ +{ + "meta": { + "code": 200, + "featureSettings": { + "useLocationMetadata": false, + "useRadarKVStore": true, + "useRadarModifiedBeacon": true, + "radarLowPowerManagerDesiredAccuracy": 3000, + "radarLowPowerManagerDistanceFilter": 3000 + }, + "sdkConfiguration": { + "logLevel": "info", + "startTrackingOnInitialize": true, + "trackOnceOnAppOpen": true + } + } +}