Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4bf3058
working-ish prototype on the example app
KennyHuRadar May 14, 2024
e763e3a
first pass implementaiton in the SDK and it compiles
KennyHuRadar May 14, 2024
b7eee43
working in the sdk but still need to clean up
KennyHuRadar May 14, 2024
987c6f6
exposed manual setting of listening on activity resume
KennyHuRadar May 15, 2024
096387a
change to use activityresultcontract and handle approximate locations
KennyHuRadar May 15, 2024
9111686
changes to the example and fix to calls
KennyHuRadar May 15, 2024
e46fe7b
clean up implementation
KennyHuRadar May 16, 2024
64d3bad
support reject background perms
KennyHuRadar May 16, 2024
2bb6b43
rename
KennyHuRadar May 22, 2024
9de9d07
add a comment
KennyHuRadar May 23, 2024
48058e9
clean up implementation
KennyHuRadar May 28, 2024
c895c9a
dont break interface
KennyHuRadar May 28, 2024
6237a6a
rename for ios parity
KennyHuRadar May 28, 2024
aa91a2e
clean up
KennyHuRadar May 28, 2024
40f9eb7
handle user revoke at bg stage
KennyHuRadar May 28, 2024
83aeca8
rename
KennyHuRadar May 30, 2024
8b317db
rename
KennyHuRadar May 30, 2024
f0c3e70
rename
KennyHuRadar May 30, 2024
bfcb5cc
add field
KennyHuRadar May 30, 2024
e55405c
version bump
KennyHuRadar May 31, 2024
579e54e
remove example changes
KennyHuRadar May 31, 2024
7e29a6a
update example
KennyHuRadar May 31, 2024
30aed97
fix plural
KennyHuRadar May 31, 2024
fc9e133
revert example changes
KennyHuRadar May 31, 2024
8bda0ce
remove space
KennyHuRadar May 31, 2024
62d0664
Merge branch 'master' into kenny-hu/fence-1912-modified-example-app-w…
KennyHuRadar May 31, 2024
2793bf5
Merge branch 'master' into kenny-hu/fence-1912-modified-example-app-w…
KennyHuRadar Oct 3, 2024
9ee03e5
fix merge
KennyHuRadar Oct 3, 2024
ac507a7
add fix from later PR
KennyHuRadar Oct 3, 2024
ff442c3
bump beta
KennyHuRadar Oct 3, 2024
d11cf08
add in on activity for android
KennyHuRadar Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Migration guides
## 3.11.x to 3.12.x
-`RadarReceiver` interface has been changed to include `onLocationPermissionStatusUpdated` method.

## 3.12.x to 3.13.x
- The `Radar.trackVerified()` method now returns `token: RadarVerifiedLocationToken`, which includes `user`, `events`, `token,`, `expiresAt`, `expiresIn`, and `passed`. The `Radar.trackVerifiedToken()` method has been removed, since `Radar.trackVerified()` now returns a signed JWT.
Expand Down
12 changes: 2 additions & 10 deletions example/src/main/java/io/radar/example/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,11 @@ class MainActivity : AppCompatActivity() {
}

private fun requestForegroundPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
} else {
Log.v("example", "Foreground location permission already granted")
}
Radar.requestForegroundLocationPermission()
}

private fun requestBackgroundPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), 2)
} else {
Log.v("example", "Background location permission already granted")
}
Radar.requestBackgroundLocationPermission()
}

private fun requestActivityRecognitionPermission() {
Expand Down
11 changes: 11 additions & 0 deletions example/src/main/java/io/radar/example/MyRadarReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import io.radar.sdk.Radar
import io.radar.sdk.RadarReceiver
import io.radar.sdk.model.RadarEvent
import io.radar.sdk.model.RadarUser
import io.radar.sdk.model.RadarLocationPermissionStatus
import kotlin.random.Random

class MyRadarReceiver : RadarReceiver() {

Expand Down Expand Up @@ -68,4 +70,13 @@ class MyRadarReceiver : RadarReceiver() {
notify(context, message)
}

override fun onLocationPermissionStatusUpdated(
context: Context,
status: RadarLocationPermissionStatus
) {
val statusString = RadarLocationPermissionStatus.stringForLocationPermissionState(status.status)
val body = "Location permission status updated: ${statusString}"
notify(context, body)
}

}
2 changes: 1 addition & 1 deletion sdk/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ apply plugin: "org.jetbrains.dokka"
apply plugin: 'io.radar.mvnpublish'

ext {
radarVersion = '3.18.0'
radarVersion = '3.19.0-beta.2'
}

String buildNumber = ".${System.currentTimeMillis()}"
Expand Down
58 changes: 58 additions & 0 deletions sdk/src/main/java/io/radar/sdk/Radar.kt
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,21 @@ object Radar {
private lateinit var replayBuffer: RadarReplayBuffer
internal lateinit var batteryManager: RadarBatteryManager
private lateinit var verificationManager: RadarVerificationManager
private lateinit var locationPermissionManager: RadarLocationPermissionManager

/**
* Used by React Native module to setup the activity.
*/
@JvmStatic
fun onActivityCreate(activity: Activity, context: Context?) {
this.context = context ?: activity;
this.activity = activity;
val application = this.context as? Application
if (!this::locationPermissionManager.isInitialized) {
this.locationPermissionManager = RadarLocationPermissionManager(this.context, this.activity)
application?.registerActivityLifecycleCallbacks(locationPermissionManager)
}
}

/**
* Initializes the Radar SDK. Call this method from the main thread in `Application.onCreate()` before calling any other Radar methods.
Expand Down Expand Up @@ -573,6 +588,11 @@ object Radar {
}
application?.registerActivityLifecycleCallbacks(RadarActivityLifecycleCallbacks(fraud))

if (!this::locationPermissionManager.isInitialized) {
this.locationPermissionManager = RadarLocationPermissionManager(this.context, this.activity)
application?.registerActivityLifecycleCallbacks(locationPermissionManager)
}

val sdkConfiguration = RadarSettings.getSdkConfiguration(this.context)
if (sdkConfiguration.usePersistence) {
Radar.loadReplayBufferFromSharedPreferences()
Expand Down Expand Up @@ -3178,6 +3198,39 @@ object Radar {
})
}
}
/**
* Requests foreground location permissions.
*/
@JvmStatic
fun requestForegroundLocationPermission() {
locationPermissionManager.requestForegroundLocationPermission()
}

/**
* Requests background location permissions.
*/
@JvmStatic
fun requestBackgroundLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
locationPermissionManager.requestBackgroundLocationPermission()
}
}

/**
* @return A RadarPermissionStatus object with the current location permissions status.
*/
@JvmStatic
fun getLocationPermissionStatus():RadarLocationPermissionStatus {
return locationPermissionManager.getLocationPermissionStatus()
}

/**
* Directs the user to the app settings to enable location permissions.
*/
@JvmStatic
fun openAppSettings() {
locationPermissionManager.openAppSettings()
}

/**
* Sets the log level for debug logs.
Expand Down Expand Up @@ -3528,6 +3581,11 @@ object Radar {
logger.i("📍️ Radar token updated | passed = ${token.passed}; expiresAt = ${token.expiresAt}; expiresIn = ${token.expiresIn}; token = ${token.token}")
}

internal fun sendLocationPermissionStatus(status: RadarLocationPermissionStatus) {
receiver?.onLocationPermissionStatusUpdated(context, status)

logger.i("📍️ Radar location permission updated | status = $status")
}

internal fun setLogPersistenceFeatureFlag(enabled: Boolean) {
this.logBuffer.setPersistentLogFeatureFlag(enabled)
Expand Down
155 changes: 155 additions & 0 deletions sdk/src/main/java/io/radar/sdk/RadarLocationPermissionManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package io.radar.sdk

import android.Manifest
import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import io.radar.sdk.model.RadarLocationPermissionStatus

class RadarLocationPermissionManager(private val context: Context, private val activity: Activity?): Application.ActivityLifecycleCallbacks {

private var danglingSettingsPermissionRequest = false
private var danglingForegroundPermissionRequest = false
private var danglingBackgroundPermissionRequest = false

private lateinit var requestForegroundLocationPermissionLauncher: ActivityResultLauncher<String>

private lateinit var requestBackgroundLocationPermissionLauncher: ActivityResultLauncher<String>

init {
if (activity is ComponentActivity) {
Log.d("LocPermissionManager", "Activity is a ComponentActivity")
requestForegroundLocationPermissionLauncher = activity.registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (!isGranted) {
RadarLocationPermissionStatus.savePreviouslyDeniedForeground(context,true)
}
Radar.sendLocationPermissionStatus(RadarLocationPermissionStatus.initWithStatus(context, activity))
// TODO: sync the user's permissions status here
}

requestBackgroundLocationPermissionLauncher = activity.registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (!isGranted) {
RadarLocationPermissionStatus.savePreviouslyDeniedBackground(context, true)
}
Radar.sendLocationPermissionStatus(RadarLocationPermissionStatus.initWithStatus(context, activity))
// TODO: sync the user's permissions status here
}
} else {
Log.d("LocPermissionManager", "Activity is not a ComponentActivity")
}
}

@RequiresApi(Build.VERSION_CODES.Q)
fun requestBackgroundLocationPermission() {
Log.d("LocPermissionManager", "requesting background")
if (activity is ComponentActivity) {
Log.d("LocPermissionManager", "calling activity")
context.getSharedPreferences("RadarSDK", Context.MODE_PRIVATE).getString("x_platform_sdk_type",null)?.let {
if (it != null) {
Log.d("LocPermissionManager", "x platform side channel")
danglingBackgroundPermissionRequest = true
}
}
requestBackgroundLocationPermissionLauncher.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
// TODO: sync the user's location permissions action with the their permissions status here
}
}

fun requestForegroundLocationPermission() {
Log.d("LocPermissionManager", "requesting foreground")
if (activity is ComponentActivity) {
Log.d("LocPermissionManager", "calling activity")
context.getSharedPreferences("RadarSDK", Context.MODE_PRIVATE).getString("x_platform_sdk_type",null)?.let {
if (it != null) {
Log.d("LocPermissionManager", "x platform side channel")
danglingForegroundPermissionRequest = true
}
}
Radar.sendLocationPermissionStatus(RadarLocationPermissionStatus.initWithStatus(context,activity,true))
requestForegroundLocationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)

// TODO: sync the user's location permissions action with the their permissions status here
}
}

fun openAppSettings() {
danglingSettingsPermissionRequest = true
val intent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts("package", context.packageName, null)
data = uri
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
context.startActivity(intent)
}

fun getLocationPermissionStatus(): RadarLocationPermissionStatus {
if (activity is ComponentActivity) {
return RadarLocationPermissionStatus.initWithStatus(context, activity)
}
return RadarLocationPermissionStatus()
}

override fun onActivityPaused(activity: Activity) {
// do nothing
}

override fun onActivityStopped(p0: Activity) {
// do nothing
}

override fun onActivitySaveInstanceState(p0: Activity, p1: Bundle) {
// do nothing
}

override fun onActivityDestroyed(p0: Activity) {
// do nothing
}

override fun onActivityCreated(p0: Activity, p1: Bundle?) {
// do nothing
}

override fun onActivityStarted(p0: Activity) {
// do nothing
}

override fun onActivityResumed(activity: Activity) {
if (danglingSettingsPermissionRequest) {
Radar.sendLocationPermissionStatus(RadarLocationPermissionStatus.initWithStatus(context,activity))
// TODO: sync the user's location permissions action with the their permissions status here
}
if (danglingForegroundPermissionRequest) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
RadarLocationPermissionStatus.savePreviouslyDeniedForeground(context,true)
}
Radar.sendLocationPermissionStatus(RadarLocationPermissionStatus.initWithStatus(context,activity))
}
if (danglingBackgroundPermissionRequest) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED){
RadarLocationPermissionStatus.savePreviouslyDeniedBackground(context,true)
}
Radar.sendLocationPermissionStatus(RadarLocationPermissionStatus.initWithStatus(context,activity))
}
danglingSettingsPermissionRequest = false
danglingBackgroundPermissionRequest = false
danglingForegroundPermissionRequest = false
}

}
8 changes: 8 additions & 0 deletions sdk/src/main/java/io/radar/sdk/RadarReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.location.Location
import io.radar.sdk.Radar.RadarStatus
import io.radar.sdk.model.RadarEvent
import io.radar.sdk.model.RadarLocationPermissionStatus
import io.radar.sdk.model.RadarUser

/**
Expand Down Expand Up @@ -56,5 +57,12 @@ abstract class RadarReceiver {
*/
abstract fun onLog(context: Context, message: String)

/**
* Tells the reciever that the location permissions status was updated.
*
* @param[context] The context.
* @param[status] The location permissions status.
*/
abstract fun onLocationPermissionStatusUpdated(context: Context, status: RadarLocationPermissionStatus)

}
Loading