Developer Reference#
Protection Status Updates#
The SDK exposes a data structure named LRProtectionStatus
that contains the SDK state. You can get it at any time in a synchronous fashion, or subscribe to receive events asynchronously anytime the status changes. The fields in the LRProtectionStatus
structure are as follows.
isProtectionActive: Boolean#
Whether a protection session is running.
vehicleType: LRVehicleType?#
Available only when isProtectionActive
is true. This reflects the parameter that was passed to startProtection()
.
Values:
on Android,
MOTORCYCLE
,BICYCLE
orCAR
on iOS,
.motorcycle
,.bicycle
or.car
sessionId: String?#
Available only when isProtectionActive
is true. This is a unique identifier for this session, generated by the SDK.
hasShockAnalysis: Boolean#
This field is for advanced use cases and might be removed in the future.
alert: LRAlert?#
When the session starts, this field is initially null. When an accident is detected, a countdown can be shown to the user to allow them to abort the accident process before an emergency is sent. This structure contains more information about this part of the process.
alertStartTime#
on Android, this is a
Long
on iOS, this is a
Date
alertDuration#
on Android, this is a
Long
on iOS, this is a
Int
emergency: LREmergency?#
When the session starts, this field is initially null. If the user does not stop the accident process during the countdown, the SDK will begin sending the emergency to SafeRider servers. This structure contains more information about this part of the process. See below for the contents.
emergencyId: String#
isEmergencySending: Boolean#
hasEmergencySendingFailed: Boolean#
isEmergencySent: Boolean#
isEmergencyCanceled: Boolean#
isEmergencyEnded: Boolean#
Fall survey answer#
After an accident alert is started, a survey can be displayed by the default screens (see US#5 - Quick Survey to cancel the Emergency). The SDK exposes a data structure named LRFallSurveyAnswer
that contains the answer to the fall survey if you are using the included accident screens. It has only one field:
hasFallen: Boolean#
The user answer.
Android#
In order to be notified when the user answers the fall survey, you can set a listener for a specific SDK event:
SafeRider.sharedInstance.fallSurveyListener = object : SafeRider.FallSurveyListener {
override fun onAnswered(hasFallen: Boolean) {
// here handle user fall survey answer
}
}
iOS#
In order to be notified when the user answers the fall survey, you have to listen the fall survey answer.
Using the LRSaferiderDelegationProtocol
:
self.safeRiderInstance.protectionDelegate = self
extension MyClass: LRProtectionDelegate {
func onFallSurveyAnswer(_ fallSurveyAnswer: LRFallSurveyAnswer?) {
log.debug("user has fallen: \(fallSurveyAnswer.hasFallen)")
}
}
Using the LRSaferiderReactiveProtocol
:
var cancellableBag = Set<AnyCancellable>()
self.safeRiderInstance.fallSurveyAnswerPublisher
.sink { fallSurveyAnswer in
log.debug("user has fallen: \(fallSurveyAnswer.hasFallen)")
}
.store(in: &self.cancellableBag)
SDK Methods#
initialize()#
Android#
initialize(context: Context, apiKey: String, notification: LRNotification? = null, tripDetectionNotification: LRNotification? = null, showAccidentUi: Boolean = true, accidentUiTextToSpeech: String? = null, accidentUiScreenLogo: Int? = nil)
iOS#
static func initialize(apiKey: String, showAccidentUi: Bool = true, accidentUiTextToSpeech: String? = nil, accidentUiScreenLogo: UIImage? = nil, accidentUiScreenLogoDarkMode: UIImage? = nil) throws
Initialize the SDK with your current api key. This method must be called from your application onCreate()
method (Android) or AppDelegate didFinishLaunchingWithOptions()
(iOS).
All the other methods require that the SDK has been initialized, otherwise they will instantly throw an error.
Initialization throws an error if the api key provided is not valid :
on Android:
UninitializedPropertyAccessException
on iOS:
LRProtectionError.invalidApiKey
Set showAccidentUi
to false to disable the included accident screens. In this case you need to implement the screens yourself following the specifications in Typical App User Stories.
If showAccidentUi
is set to true, you could:
set
accidentUiTextToSpeech
to customize the message that is sent to speech synthesis during an accident. By default it will be “Accident alert”set your rectangular logo to
accidentUiScreenLogo
: it will be displayed at the top of all the accident workflow’s screens(on iOS only) set your dark mode rectangular logo
accidentUiScreenLogoDarkMode
too if your app manages the dark mode and youraccidentUiScreenLogo
is not optimized for it.
NB: if you do not set at least accidentUiScreenLogo
in this case, it will be the Liberty Rider’s logo that will be displayed on relative screens.
For explanation on the notification parameter on Android, please refer to Notification for Foreground Service. Set a custom notification that will be used by the SDK to bind its “foreground service”, as required since Android 8 to allow applications to run in background. This parameter is not available on iOS.
startProtection()#
Android#
startProtection(vehicleType: LRVehicleType, userId: String, phoneNumber: String, firstName: String?, lastName: String?, metadata: Map<String, Any>?) : LRStartProtectionResult
iOS#
Using the LRSafeRiderDelegationProtocol
:
func startProtection(vehicleType: LRVehicleType, userId: String, phoneNumber: String, userFirstName: String?, userLastName: String?, metadata: [String : Any]?)
Using the LRSafeRiderReactiveProtocol
:
func startProtection(vehicleType: LRVehicleType, userId: String, phoneNumber: String, userFirstName: String?, userLastName: String?, metadata: [String : Any]?) -> AnyPublisher<Void, LRProtectionError>
Start a new protection session. Parameters:
vehicle type which allows to choose between .motorcycle or .bicycle support
- user identity, which will be used by our operators and emergency services:
phone number (mandatory)
unique identifier of the user account (mandatory)
first name
last name
some metadata (optional) for this session or ride. It can be used to link ride data from your information system to a specific emergency on SafeRider servers.
The SDK needs some guarantees before starting a session, otherwise it will throw an error instantly:
You need to have initialized the SDK
Your mobile application needs to have been granted a location permission. See the platform specific section of this document for more information.
The phone number must have an international prefix and respect this regex format:
^[+][1-9][0-9]{6,14}$
stopProtection()#
Stop a protection session that was previously started with startProtection()
. This method has no effect if status.isProtectionActive
is false.
stopAlertCountdown()#
Stop an alert countdown that started during an ongoing protection session. This method has no effect if status.alert
is null.
cancelEmergencyRequest()#
Cancel an emergency that is being sent or has already been sent.This method has no effect if status.emergency
is null.
resumeProtectionAfterEmergency()#
After an emergency was sent, resume sensor processing to detect new accidents. This method has no effect if status.emergency
is null or status.emergency.isEmergencySent
is false or status.emergency.hasEmergencySendingFailed
is false.
reportProblem()#
If you notice a problem during a protection session, you can report a problem. This will upload debug information to SafeRider servers.
iOS#
Using the LRSaferiderDelegationProtocol
:
self.safeRiderInstance.problemReportDelegate = self
extension MyClass: LRProblemReportDelegate {
func onProblemReportSuccess() {
log.info("succeed to report problem")
}
func onProblemReportFailure(_ error: LRProtectionError) {
log.error("fail to report problem: \(error.localizedDescription)")
}
}
Using the LRSaferiderReactiveProtocol
:
var cancellableBag = Set<AnyCancellable>()
self.safeRiderInstance.reportProblem()
.sink { completion in
switch completion {
case .failure(let error):
log.error("fail to report problem: \(error)")
default: break
}
} receiveValue: { _ in
log.debug("succeed to report problem")
}
.store(in: &self.cancellableBag)
setFallSurveyAnswer(hasFallen)#
Set the fall survey user answer if you have implemented your own accident workflow UI.
Debugging#
These methods allow you to debug or test your SDK integration from a developper-only menu.
triggerFakeAlertCountdown(location)#
Start a fake alert countdown, short-circuiting the accident detection algorithms.
Location parameter type is:
on Android,
android.location.Location
on iOS,
CoreLocation.CLLocation
sendFakeEmergencyRequest(location)#
Send a fake emergency to SafeRider servers, bypassing the accident detection algorithms and the alert countdown.
Location parameter type is:
on Android,
android.location.Location
on iOS,
CoreLocation.CLLocation
simulateFakeShock(date)#
Simulate a fake shock in the accident detection algorithm. This method is for advanced use cases and might be removed in the future.
Date parameter type is:
on Android,
java.lang.Long
(Date in milliseconds)on iOS,
Date
Errors#
Android#
LRStartProtectionResult#
Result of the startProtection()
command. It indicates if the protection has been activated successfully or not. In case protection can’t be started the corresponding error is returned.
Errors can also be checked via getConfigurationErrors()
method on the SafeRider instance.
Fields:
isActive
: Booleanerror
:LRProtectionError?
LRProtectionError#
Class which represents protection errors. It contains a field (isBlockingError
) to indicate if the error must be resolved in order to start protection.
EmptyUserId#
Blocking
This error can be returned from startProtection()
. An userId
must be provided in order to start protection.
InvalidPhoneNumber#
Blocking
This error can be returned from startProtection()
. A valid phone number must be provided in order to start protection.
LocationPermissionNotGranted#
Blocking
This error can be returned from startProtection()
or getConfigurationErrors()
. Location permission must be granted to start protection.
BackgroundLocationPermissionNotGranted#
Blocking
This error can be returned from startProtection()
or getConfigurationErrors()
. Background Location permission must be granted to start protection.
GpsDisabled#
Blocking
This error can be returned from startProtection()
or getConfigurationErrors()
. Gps must be enabled to start protection.
LocationDisabled#
Blocking
This error can be returned from startProtection()
or getConfigurationErrors()
. Location must be enabled to start protection.
BatterySavingEnabled#
Non blocking
This error can be returned from getConfigurationErrors()
. Any battery saving feature should be disabled in order to have reliable protection.
BackgroundProcessingNotGranted#
Non blocking
This error can be returned from getConfigurationErrors()
. Background processing should be allowed in order to prevent applications from being killed in background.
iOS#
enum LRSafeRiderError: Int, Error {
/// 10xxx: iOS problems
case iOSLocationServicesDisabled = 10000
case iOSLocationAuthorizationNotGranted = 10001
case iOSMotionActivityAuthorizationNotGranted = 10002
/// 12xxx: sdk problems
case invalidApiKey = 12000
case notInitialized = 12001
case invalidPhoneNumber = 12002
case emptyUserId = 12003
/// 13xxx: operation calls
case operationFailed = 13000
case operationInvalidCall = 13001
public var localizedDescription: String {
switch self {
case .iOSLocationServicesDisabled:
return "You should enable location services"
case .iOSLocationAuthorizationNotGranted:
return "You should request and grant Location authorization (at least 'when in use' before start protection)"
case .iOSMotionActivityAuthorizationNotGranted:
return "You should request and grant Motion & Fitness authorization"
case .invalidApiKey:
return "You have to provide a valid api key"
case .notInitialized:
return "You have to call initialize(apiKey: String) before calling any function"
case .invalidPhoneNumber:
return "You should provide a valid phone number (ex: +33600000000 for France)"
case .emptyUserId:
return "You should provide a not empty user id"
case .operationFailed:
return "The operation has failed"
case .operationInvalidCall:
return "The operation can not be called considering current protection status"
}
}