ODK SMS Bridge
An app for sending SMS messages with and without user confirmation.
Overview
The ODK SMS Bridge lets you send SMS messages with an Intent. Sending SMS messages via Intents is supported by default in Android. Unfortunately, doing so always launches a messaging app and requires user confirmation.
Android 4.4 introduced the SmsManager, which lets you send messages without an external app. However! There is no way to trigger it using an Intent.
This app is a small wrapper around both methods that lets you use either
technique via an Intent. A require_confirmation
boolean variable selects
which method is used.
While not currently on the Play Store, you can download the latest snapshot build here.
For more information on the Open Data Kit (ODK) project, please see the project homepage or developer page.
Usage
The ODK SMS Bridge is designed to be called from other apps via Intents. However, the welcome screen of the app lets you enter a phone number and message body and send messages using both supported techniques: with and without user confirmation.
In this way you can see what the user will experience when using your app.
In Native Android Apps
Interact with the ODK SMS Bridge using an Intent. Arguments maybe be passed in the extras Bundle.
The code below sends a message to number 3605551234
with the content This is a fancy message.
.
Intent intent = new Intent();
ComponentName componentName = new ComponentName(
"org.opendatakit.smsbridge",
"org.opendatakit.smsbridge.activity.SMSDispatcherActivity");
intent.setComponent(componentName);
Bundle bundle = new Bundle();
// False to send an SMS immediately without the user stepping in.
// True to require user intervention.
bundle.putBoolean("require_confirmation", false);
bundle.putString("message_body", "This is a fancy message.");
bundle.putString("phone_number", "3605551234");
intent.putExtras(bundle);
context.startActivity(intent);
In ODK Survey
The ODK SMS Bridge can also be called from ODK Survey by defining a custom prompt type. See the ODK page for more information.
Custom prompts are defined in a file called customPromptTypes.js
.
If your form ID is my_form
, and the ID of the table this form saves data to
is my_table
, the full path of this file would be
app/my_table/forms/my_form/customPromptTypes.js
.
In this example we'll define a new prompt type called send_sms
and use it in
a form.
The files are explained below. You can also find the files themselves in the surveyFiles directory.
First, let's set up our form. It will consist of three prompts: a name, a phone number, and the button that sends an SMS.
This will require three worksheets: survey
, prompt_types
, and settings
.
Our survey
sheet will look like this:
type | name | display.text |
---|---|---|
text | name | Enter a Name |
text | phone_number | Enter a Phone Number |
send_sms | send_message | Send an SMS |
Our prompt_types
sheet will define our custom send_sms
type:
prompt_type_name | type |
---|---|
send_sms | integer |
Note! In this example we're not actually saving anything in this prompt, so the type doesn't matter.
And finally our settings
sheet looks like this:
setting_name | value | display.title |
---|---|---|
form_id | sms_example | |
form_version | 20141011 | |
survey | SMS Example | |
table_id | sms_example |
And now we need to tell Survey what to do with our custom prompt type. This
happens in the customPromptTypes.js
file, which should be placed in the same
directory as the .xlsx
file defining the form and the formDef.json
file.
define(['promptTypes', 'jquery', 'underscore', 'prompts'],
function(promptTypes, $, _, prompts) {
return {
'send_sms': promptTypes.launch_intent.extend({
type: 'send_sms',
datatype: 'send_sms',
buttonLabel: {
'default': 'Send an SMS'
},
// The bulk of this function was taken from a launch_intent prompt
// in prompts.js. This is only needed if you need to access data
// collected in the same form when sending an SMS. All the
// statements except those beginning with that.intentParameters
// need to remain in order to preserve normal functionality.
configureRenderContext:
function(ctxt) {
var that = this;
var value = that.getValue();
// We'll overwrite the default message with our custom message.
that.intentParameters.extras.message_body =
'Hello, ' +
that.database.getDataValue('name') +
'!';
that.intentParameters.extras.phone_number =
that.database.getDataValue('phone_number');
that.renderContext.value = value;
that.renderContext.buttonLabel = that.buttonLabel;
ctxt.success();
},
intentString: 'org.opendatakit.smsbridge.activity.SMSDispatcherActivity',
intentParameters: {
extras: {
require_confirmation: true,
message_body: 'Default message body',
}
}
})
};
});
Note! If you don't want to require user confirmation, set the
require_confirmation
variable to false. However, be aware that the app currently doesn't aim to gracefully handle the case where there is no cell service.
The generated form will have three questions on three different screens. The first will collect a name, the second a number, and the third will be a button that sends an SMS. Clicking the button will ask for user confirmation and send a message saying hello to the entered phone number.
Architecture
SMS messages are sent by the SMSDispatcherActivity. This activity has no user interface. It interprets arguments passed via an Intent (see Usage) and finishes immediately. This is the Activity callers should invoke.
The main screen of the app is the WelcomeActivity. It exists to allow
users to see what interactions with the SMSDispatcherActivity
are like. Two
buttons let you send a message with or without user confirmation to give you a
sense of the different user experiences.
Building and Contributing
The original structure of the project came from deckard-gradle. Follow their setup instructions to build the project.
It uses the Android Gradle build system.
Tests
Tests can be run from the root directory with the command
./gradlew clean test
.
They can also be run within IntelliJ, provided you follow the setup instructions from deckard-gradle.
Not Currently Supported by Core ODK Team
This app is currently not supported by the core Open Data Kit (ODK) team.
However, this is a supported project. Feel free to open issues and use it, but for now you can't necessarily count on support from the entire ODK core team.