This codument covers the protocol (SABRE) for using a separate Android application for communication with crowd-sourced data exchange servers.
The following definitions are used in this document:
The following key considerations are assumed:
<packageName>.MainBroadcastReceiver
as a receiving class (this is needed to overcome broadcast limitations added in Android O)data
string extra field of an intentThis document uses YAML representation for messages in examples for easier reading; however, in actual applications, the pure JSON must be used.
In order to be discovered, all proxy apps must have package name starting with app.sabre.
, followed by a plugin name.
The host application
app.sabre.
,The handshake broadcast has following contents:
ACTION: app.sabre.HANDSHAKE
CONTENTS:
protocol_version: 1
response_action: "@action_discovery_response"
@package_name
is the package name of the host application. The action of intent should look like app.sabre.<plugin_name>.HANDSHAKE
.
protocol_version
is an integer. 1
must be used for implementations in accordance with this document; this should be changed only on non-bachward-compatible protocol updates. This number must match the major version number in the heading of this document.
@action_discovery_response
is generated by the host app and shows, which action should be used by the proxy app to send the response.
Once a proxy app receives a message from this channel, it must response with another broadcast message.
ACTION: @action_discovery_response
CONTENTS:
id: "@proxy_id"
name: "@proxy_name"
version: "@proxy_version"
supported_sources: [
"id": @source_id
"name": @source_name
],
request_action: "@action_fetch_request"
report_action: "@action_submit_report"
confirm_action: "@action_confirm_report"
discard_action: "@action_discard_report"
shutdown_action: "@action_shutdown"
alternative_startup_activity: "@activity_alternative_startup"
@proxy_id
is the ID that should be the same for every launch. This way the host app can store some internal data sprcific for the proxy app. The Android’s installation ID should work perfectly for this.@proxy_name
is how the host app should present the proxy to the user@package_name
the name of the proxy package (should start with app.sabre.
)@proxy_version
is also for display purposessupported_sources
lists the sources that the proxy can work with, the host app may decide (or let user to choose) to leave reports from only some of them@source_id
is the ID of source that shouldn’t change over time, should be used by the host to identify the source@source_name
is the name of the source which can be presented to the end user, may change over time@action_fetch_request
is where messages requesting the alerts data should be sent to@action_submit_report
, @action_confirm_report
, and @action_discard_report
are where reporting, confirming, and “not there” messages should be sent to@action_shutdown
is a channel for the host app to notify proxy that there are no more requests expected, and the proxy app may free caches/resouces, and stop required services.@activity_alternative_startup
is an activity to be used in the alternative startup procedure. See below for details. (IMPORTANT: this field was introduced in protocol v1.1 and may not be present in the response). Assume that alternative startup isn’t available if the field isn’t presented.The proxy app shouldn’t assume the discovery broadcast will always be sent (e.g. the host app may cache the data), and must wake up on any incoming broadcast having the correct action.
On newer Android version, requests has to be processed in a foreground service. It is a good practice for a host app to notify, when the proxy isn’t needed any more, so it can immediately shut down the service and, thus, remove the mandatory notification.
In order to notify the proxy that it can shut down the service, it should send an empty broadcast with action @action_shutdown
.
The proxy app shouldn’t assume the shutdown broadcast will always be sent (e.g. the host app may crash), and must shutdown itself after several minutes of no incoming broadcasts.
Some devices have incorrectly configured firmware, blocking background apps from staring foreground service even on an explicit intent. For such cases host app may support and alternative method for waking up the proxy app. It is recommended to let user enabled the alternative startup manually, and have it disabled by default.
Alternative startup sequence:
@activity_alternative_startup
. (ComponentName("sabre.app.<appname>, @activity_alternative_startup)
) This brings the proxy app to the foreground.
callback_app
, and callback_component
.callback_app
and callback_component
extras from the first step.Using the alternative startup flow allows the proxy app to start its foreground service while being displayed. This overcomes limitations of some firmwares. The downside of this flow is that the proxy application is temporarily displayed on the screen during the start-up.
Notes
FLAG_ACTIVITY_NEW_TASK
when starting activities from other apps.Alerts fetching works using the request-response model. In order for the host app to fetch an alert, it sends a broadcast with the following contents:
ACTION: @action_fetch_request
CONTENTS:
request_id: "@request_id"
lat: @latitude
lon: @longidute
radius_m: @radius
response_action: "@action_fetch_response"
@request_id
is a unique string for the host app to be able to match requests with responses@latitude
, @longitude
, and @radius
are floats. Radius is set in meters.response_action
is a broadcast action where the response must be sentThe proxy app fetches the required data and sends the following respose back:
ACTION: @action_fetch_response
CONTENTS:
request_id: "@request_id"
error_message: "@error_message"
response:
n_batches: @n_batches
batch_id: @batch_id
alerts: [
alert_source: "@alert_source"
alert_id: @alert_id
type: "@alert_type"
lat: @latitude
lon: @longitude
heading_deg: @heading
street_name: "@street_name"
report_ts: "@report_ts"
confirm_ts: "@confirm_ts"
n_confirmations: "@n_confirmations",
is_response_accepted: "@is_response_accepted",
speed_limit: "@speed_limit",
]
@request_id
is the same as in requesterror_message
and response
are nullable fields. Exactly one of them must be set, depending on the outcome of the request@error_message
is a short human-readable message which can be displayed the the end user@n_batches
is the total number of messages response for this response; as messages may get large and not fit into the maximum allowed broadcast message size, the proxy app may decide to split the response into multiple messages.@batch_id
is the ID number of the current batch; there should be total @n_batches
batches with IDs from 0
to @n_batches - 1
@alert_source
is the id which must be present in the supported_sources
section of the discovery response@alert_id
is the unique ID of a given alert; it can be used to track the same alerts between different requests, and to confirm/discard reports in further section@latitude
, @longitude
, and @heading_deg
are floats. Heading is set in degrees, clockwise from the true north.@street_name
is an nullable string, containing the street name of an aleert@report_ts
is a UNIX timestamp, specifying when the alert was reported@confirm_ts
is an nullable field, containing UNIX timestamp, specifying when the alert was last confirmed by any user@n_confirmations
is an integer field showing number of times the alert was confirmed. (IMPORTANT: this field was introduced in protocol v1.1 and may not be present in responses)@is_response_accepted
is a boolean, denoting whether this alert can be used with confirm/discard methods. Normally this evaluate to false
for own submissions, and for data sources not supporting confiming/discarding alerts. (IMPORTANT: this field was introduced in protocol v1.1 and may not be present in responses; assume it being equal to true
if not present)@speed_limit
is a nullable float field, that may be set for some alerts (e.g. for mobile cameras). (IMPORTANT: this field was introduced in protocol v1.1 and may not be present in responses)@alert_type
must be one of predefined alert types, allowed types are:
POLICE_VISIBLE
POLICE_HIDING
ACCIDENT_MINOR
ACCIDENT_MAJOR
HAZARD_ON_ROAD
HAZARD_ON_SHOULDER
HAZARD_WEATHER
HAZARD_ON_ROAD_OBJECT
HAZARD_ON_ROAD_POT_HOLE
HAZARD_ON_ROAD_ROAD_KILL
HARARD_ON_ROAD_CAR_STOPPED
HAZARD_ON_SHOULDER_CAR_STOPPED
HAZARD_ON_SHOULDER_ANIMALS
HAZARD_ON_SHOULDER_MISSING_SIGN
HAZARD_WEATHER_FOG
HAZARD_WEATHER_HAIL
HAZARD_WEATHER_HEAVY_RAIN
HAZARD_WEATHER_HEAVY_SNOW
HAZARD_WEATHER_FLOOD
HAZARD_WEATHER_MONSOON
HAZARD_WEATHER_TORNADO
HAZARD_WEATHER_HEAT_WAVE
HAZARD_WEATHER_HURRICANE
HAZARD_WEATHER_FREEZING_RAIN
HARARD_ON_ROAD_LANE_CLOSED
HAZARD_ON_ROAD_OIL
HAZARD_ON_ROAD_ICE
HAZRAD_ON_ROAD_CONSTRUCTION
FIXED_CAMERA
(new in SABRE v1.1)MOBILE_CAMERA
(new in SABRE v1.1)END_OF_TAILBACK
(new in SABRE v1.1)The following message is used to report an alert
ACTION: @action_submit_report
CONTENTS:
lat: @latitude
lon: @longitude
heading_deg: @heading
altitude_m: @altitude
type: @alert_type
is_opposite: @is_opposite
time_delta_s: @time_delta
test: @test
@latitude
, @longitude
, and @heading
follow the same format as in the previous sections of this document; they describe where the report should be placed to@altitude_m
is a float, representing the GPS driver’s altitude@alert_type
is the same as in the reporting section of this document@is_opposite
is a boolean@time_delta_s
(integer) specifies, how many seconds has passed since the reporting event, until this message@test
(boolean, new in SABRE v1.2) specifies if the request should actually be sent, if set to false than the SABRE plugin should produce the same interaction, but not actually send the report.The send action expects no response (fire and forget). If the action has failed, the proxy app may notify the user by showing a toast message.
In order to confirm a report the following message should be sent
ACTION: @action_confirm_report
CONTENTS:
lat: @latitude
lon: @longitude
alert_id: @alert_id
test: @test
@alert_id
must match the one received from the response message.@latitude
and @longitude
represent current driver position@test
(boolean, new in SABRE v1.2) specifies if the request should actually be sent, if set to false than the SABRE plugin should produce the same interaction, but not actually send the report.The confirm action expects no response (fire and forget). If the action has failed, the proxy app may choose to notify the user by showing a toast message.
In order to decline a report the following message should be sent
ACTION: @action_discard_report
CONTENTS:
lat: @latitude
lon: @longitude
alert_id: @alert_id
test: @test
@alert_id
must match the one received from the response message.@latitude
and @longitude
represent current driver position@test
(boolean, new in SABRE v1.2) specifies if the request should actually be sent, if set to false than the SABRE plugin should produce the same interaction, but not actually send the report.The discard action expects no response (fire and forget). If the action has failed, the proxy app may notify the user by showing a toast message.