Android Toolkit¶
This is an optional addition that offers standard UI controls actions that requires interaction with the user, for example open a popup browser within your app. This makes the CGIBeaconPlatform work out-of-the-box, but also offers flexibility to allow the use of your custom controls for a completely seamless integration with your application.
Setup¶
Implementing CGI Beacon framework for Android is as simple as adding two aar files into your lib folder. This requires that your working environment supports aar files, but for native implementations this is not a problem. If you are implementing the framework in a cross platform environment like Titanium or Phonegap you will need to unzip the aar files and import the classes.jar files to your lib, and then add the necessary lines in the manifest to make them run.
Toolkit¶
Toolkit.java is a default implementation of the frameworks toolkit. It includes everything that you need to initialize and start using CGI Beacon framework. It extends BeaconTrackActivity, which listens for brodcasts from the BeaconService, and then calls the corresponding callbackfunction and takes the appropriate action. Depending on your needs, you can choose to let the superclass BeaconTrackActivity handle all, some or minimal logic. If you want it to handle minimal amounts of logic, you intercept the url/message signals, by @Override-ing the callback methods, and if you want it to handle everything, you just need the initiation step. Below is an example of how you would override the onActionMessage inside the function is how the framework currently functions and this is the part which could be modified:
@Override
public void onActionMessage(String msg){
alertMsg("ActionMessage",msg);
}
Initation¶
onCreate in Toolkit.java includes the minimal required code to initialize the beacon tracking service. This includes checking and if needed turning on the bluetooth adapter:
if (!BeaconUtils.checkBluetoothAvaliability())
{
BeaconUtils.turnOnBluetoothIfNotAvaliable(this);
}
And then calling restartBeaconTrackService() from BeaconTrackServiceHelper.java. This method takes 6 or 8 parameters as input, in order:
- Application - The application context
- apiKey - A string
- apiSecret - A string
- Google Analytics ID - A string
- GCM ID - A string
- Server URL - A string
- Icon (integer) - An integer
- Cient_Object - A JSON string
Example:
BeaconTrackServiceHelper.restartBeaconTrackService (Application,
apiKey,
apiSecret,
Google_Analytics_ID,
GCM_ID,
Server_URL,
Icon,
Client_Object);
So either you call the method with 6 parameters (excluding GCM ID (#5 in the list) and Client_Object (#8 in the list)), or you call it with all 8. If you want to use a custom icon for notifications then send the resource id as the icon parameter. Otherwise set the icon parameter to -1 and the framework will use the applicationIcon for notifications. After this method is called, the framework will request the application data/manifest from the server. When the initiation is completed onBeaconServiceConnected will be called, in which we set the scan periods and then call rescheduleMonitoring, which make the service start scanning for the regions (beacons) that has been configured for the application on the server.
The icon given in the method will be used when the framework sends a notification. A notification is sent when the application is in backgroundMode and a url or message event is triggered.
Additionally Toolkit.java sets backgroundMode and StartOnDeviceBoot to true in onCreate, which means that the Service will always scan for beacons in the background, and will automatically start up when the device is booted/rebooted. The service will keep running even when the user kills the app by swiping it away from the “recent apps” list, but when the main activity is killed we cannot call the callbackfunctions. When the service triggers an event and the application is in backgroundMode or killed, a notification is sent, with a launchIntent. This means that when the user clicks on the notification the application will be restarted, or brought to foreground if it is only in backgroundMode. In order to handle the event when this happens, we need to read the intent-extras in onCreate method of the application. You can choose to manually check the extras and take appropriate action, or simply call the handleIntent(intent) method and this is taken care of.
Callback Methods¶
There are 4 main callbackmethods in the toolkit:
- onBeaconServiceConnected()
- onActionMessage()
- onActionShowUrl()
- onActionTaken()
The first is merely a middle step in the initiation process, while the other 3 are events triggered.
onBeaconServiceConnected()¶
This callback is designed to let the application preform actions after the service is ready, but before the actual scanning is started. In Toolit.java this is used to set the scanning periods to 5 seconds both in background and foreground. By default they are set to 1.1 seconds in foreground and 10 seconds in background.
onActionMessage()¶
This callback is called whenever a message event is triggered. A typical message event is triggered when the service finds a beacon in range, which has either a message action attached or a timedMessage. A timedMessage will of course only be triggered if the current date and time matches any of the given dates and times.
Depending on parameters set on the action, the event could also be triggered by leaving a region (no longer picking up the beacon signal), or being within a given distance. We are currently expanding the conditions available for all actions, and the configuration is already available on the server, however the android framework dos not yet support this. A new version with this feature included will be available very soon though, and this will render the timedMessage type redundant.
onActionMessage callback receives only one parameter, which is a string with the message. The default behavior of this callback method is to call the helper function alertMsg() with title “ActionMessage” and the message as text, which will create a popup-dialog.
onActionShowUrl()¶
This callback is called when a URL event is triggered. Similarly to onActionMessage, the variables for when the event is triggered is configured on the server, and handled in the framework, and if they are met, the callback is triggered. This callback takes a few more parameters as input:
- URL (string)
- title (string)
- description (string)
- userconfirm (string)
- type (string)
Userconfirm determines if a dialog should be displayed where the user confirm or cancel the request to show a webpage. This parameter is configured as a free string on the server right now, so values could be either:
1/0
yes/no
YES/NO
or even something totally different, however the values SHOULD be “1” or ”0”. There is also a free text input, but the accepted values are external, popup or fullscreen or none. However to be sure, you should have a fallback for if either of these parameters are set as nothing to ”” or NULL, or an unaccepted string value. Description and title are used as corresponding texts for the notification, but can also be used for the confirm dialog.
The URL parameter is the actual URL for the webpage to be shown, however this actionType can also be used to open other protocols. An example usage was to open another application on made in the CGI Gothenburg office, which had a specific protocol.
The default behavior of the callbackfunction is to check userconfirm, and then either calls the helperfunction openWebView() directly, or via webMsg() which is a modified version of alertMsg() but with ok/cancel buttons. The ‘ok’ button in a webMsg will call openWebView().
onActionTaken()¶
The third and final callback is used for logging of actions. Every time an event is triggered, this will be called with a HashMap containing parameters for the event. This includes both events that do trigger the previous two callbacks, and events that does not. Examples of events that do not trigger any callback are “eventLog”, “GATrackEvent” and “GATrackPage” which are all handled by the framework directly.
The HashMap supplied will contain the following attributes:
- type (string)
- date (long)
- Id (int)
- pkId (int)
Type is the actionType string, date is a date object in Long format, id is the actionId and pkId is the unique identifier used when calling rehandleAction() in the framework.
The intention of this callback is to give the application the opportunity to log and/or display the events that have occurred, and additionally there is the opportunity to rehandle this action. When an action is rehandeled, it is simply preformed once more, with the key difference being that no proximity conditions such as distance are checked, and neither is timeout. Time and date conditions are checked though, as the message may vary depending on time. Rehandeled actions are not added to the eventhistory either, which means that the “eventLog” action is effectively doing nothing when it is rehandeled.
The toolkit does not yet have a default method for rehandeling actions implemented, so in order to rehandle an action, you need to manually broadcast an intent matching the snippet below:
packageString = getPackageName(); Intent rehandleIntent = new Intent(BeaconTrackService.ACTION_REHANDLE+packageString); rehandleIntent.putExtra(“pkId”, index);
ACTION_REHANDLE is a public final string in the framework uniquely identifying which action to take, and the package of the application is added at the end, to avoid signals getting mixed when the framework is implemented in more than one application on the device.
Helper Methods¶
As mentioned earlier in this document, you can choose to which extent you let the toolkit handle the logic. If you want to completely control what to do with the action-signals received, then just override the callback methods above and write your own code. If you want to leave it completely to the default behavior, then just extend BeaconTrackActivity and preform the initiation and everything else will be handled in by the framework. But for anything in between these two, all logic has been placed into a set of helper methods, that can be called or modified (by using @Override) at your will. In this section the complete set of helper methods will be explained.
handleIntent()¶
As the name suggests, this method will handle intent. The method is intended to be called in onCreate with the launchintent as argument, but it can be used for any intent that has the corresponding extras. The method will check what extras are attached to the intent and, based on the extras, call one of three helper methods (alertMsg, webMsg or openWebView) with the specific extras as parameters.
alertMsg()¶
This helper method will take two strings as arguments and create a popup dialog. The dialog will have ‘title’ as title and ‘text’ as message, and it will only have one button with the text ‘Ok’ that will cancel the dialog when pressed. This method is used for message events by default, but can be used for any message that you need to display in the app.
webMsg()¶
This helper method is an extended version of alertMsg(). It takes two additional parameters as argument,**url and type**, and is used for url events which is set to have userconfirm. The method will create a popup dialog just like alertMsg, but it will have two buttons; ‘Ok’ and ‘Cancel’. Both of these buttons will “cancel”(close) the popup, but the ‘Ok’ button will also call the helper method openWebView with url and type as arguments.
openWebView()¶
This helper method takes two strings as arguments, and creates a webView, which is then added to the contentView. The default behavior is to always act as if the type is defined as ‘FULLSCREEN’, so the parameter ‘type’ is always ignored. The url is loaded to the webview after it has been added to the contentView. By default the webview does not have its own toolbar, however the toolkit comes with an actionBar that contains an optionItem to return to homescreen, which is used to close the webview.
closeWebView()¶
This helper method is used to close the webview, and as we define the webview globally in the toolkit it does not need any parameters as input. It will remove webview from the contentView, which effectively brings the application ‘back’ to the homescreen.
Notes¶
While the first 3 helper methods can be used as they are for most implementations, the four last methods might not. Webview and actionBar will most likely be very dependent on the context and layout of the application, and will in most cases need to be modified or completely rewritten. Remember that if you @Override the openWebView() method you will most likely need to modify the closeWebView() method as well. And if you remove the actionBar, it would be recommended that you find another way to call closeWebView().
Example Code¶
The minimum amount of code that is required to get the framework up and running is pretty much:
if (!BeaconUtils.checkBluetoothAvaliability()) {
BeaconUtils.turnOnBluetoothIfNotAvaliable(this);
}
BeaconTrackServiceHelper.restartBeaconTrackSerivce(getApplication(),"com.cgi.androidtest", "android", "UA-55289312-1", "12345678910","https://stage.beaconplatform.io/api/v2/", -1, "");
Adding these two snippets of code to your main activity inside the auto-generated onCreate() function and making sure that your activity extends BeaconTrackActivity should be sufficient to get it upp and running.
By default the framework will handle the actions linked to the triggers associated with the key sent to the platform. These functions can naturally also be overridden and customized.
The values in the in the example should of course be changed to your own key otherwise the framework will not know which triggers you are interested in and which actions it should take if they are triggered.
This is some basic example code that along with the other functions within Toolkit.java and a layout with the matching views will create a simplistic application, which will take a demoKey as input and preform the action that is linked to demoKey in the Beacon Platform.
public class Toolkit extends BeaconTrackActivity {
private String parentPackage = "";
public Toolkit theContext = this;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContext(this);
parentPackage = getPackageName();
Receiver r = new Receiver();
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
if (!BeaconUtils.checkBluetoothAvaliability()) {
BeaconUtils.turnOnBluetoothIfNotAvaliable(this);
}
TextView btnLogin = (TextView)findViewById(R.id.btnLogin);
btnLogin.setOnClickListener(new View.OnClickListener(){
public void onClick(View v){
EditText etInput = (EditText)findViewById(R.id.etInput);
String strUserInput = etInput.getText().toString();
if(strUserInput != ""){
sendDemoKey(strUserInput, theContext);
}
}
});
BeaconTrackServiceSettings.setAlwaysWorkInBackground(Toolkit.this, true);
BeaconTrackServiceSettings.setStartOnDeviceBoot(Toolkit.this, true);
/*
* When the launchintent has extras, it means the activity was started from a notification.
* When this happens we need a separate handler to read the information of the intent and take the appropriate action,
* as the activity was not active when the initial broadcast was sent, and couldn’t receive it
*/
if(getIntent().getExtras()!=null){
handleIntent(getIntent());
}
}
private void sendDemoKey(final String demoKey, final Toolkit context) {
new AsyncTask<String,Void,Void>() {
public Toolkit tk = context;
@Override
protected Void doInBackground(String... params) {
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
InputStream inputStream = null;
String result = null;
String url = "";
try {
URI uri = new URI("https://demo.beaconplatform.io/demoapi/"+ demoKey + "/");
HttpGet httpget = new HttpGet(uri);
response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
inputStream = entity.getContent();
// json is UTF-8 by default
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
result = sb.toString();
JSONObject jObject = new JSONObject(result);
String apiKey = jObject.getString("apiKey");
url = jObject.getString("url");
final String url2 = url;
Boolean toolbar = jObject.getBoolean("toolbar");
Log.d("JSON Response", "" + apiKey + " AND " + url);
Handler mainHandler = new Handler(Looper.getMainLooper());
mainHandler.post(new Runnable() {
public void run() {
tk.openWebview(url2, "");
}});
BeaconTrackServiceHelper.restartBeaconTrackSerivce(getApplication(), apiKey, "thisisthedemoapisecret", "UA-55289312-1", "https://demo.beaconplatform.io/api/v2/", -1);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
finally {
try{if(inputStream != null)inputStream.close();}catch(Exception squish){}
}
return null;
}
}.execute(demoKey, null, null);
}
Naturally some variables will have to be changed in order for the code to run smoothly with your application and actions. The first function, which is the main function of Toolkit.java basically reads the user input which should be the demoKey and sends to the second function which sends it along with a few other variables to the Beacon Platform which in return will send the action or actions linked to the specific key. Which the Framework will then handle accordingly.
Additional Notes¶
This is a first revision of the documentation made for the first version of the Android beaconframework, so if there are any questions, suggestions for added features/functionality or suggestions for added explanation in the documentation, please contact Joachim Haglund by email: joachim.haglund@cgi.com