Creating a Beacon App for Android in Less Than 10 Minutes From Scratch
Note
When I decided to relaunch my blog, I initially removed all the old posts from the server assuming that they were no longer being viewed. However, checking the server logs revealed ongoing access attempts for two specific blog posts from about ten years ago.
Given this unexpected interest, I decided to republish these posts to make them available again. One post is about Android and beacons, which was originally published on February 5, 2015.
The only change made to this post is the removal of an external link that no longer leads to the original vendor’s site; otherwise it remained unchanged. Maybe they’re still useful for someone out there!
Original Article
Before starting to create a Beacon app for Android a few words about Bluetooth.
Bluetooth Low Energy (BLE)
Compared to classic Bluetooth, Bluetooth Low Energy consumes much less power (e.g. 0.01 W instead of 1W), the BLE devices are considerable cheaper to build, but the data transfer rate is much lower (e.g. 0.27 Mbit/s).
Great applications for BLE are scenarios where the power consumption must be low and the data rate is not important, e.g. the communication with small wearables, watches and fitness equipment and so on.
So it was only logical when Apple decided to use BLE as base technology for their small passive transmitters called iBeacons®.
Beacons
Beacons are permanently sending out their unique identifier to notify nearby smartphones of their existence, hence the name beacons. A compatible app running on the smartphone then knows that it is in a close proximity. Depending on the application, this can trigger an action on the smartphone, e.g. displaying some information about nearby items.
Beacons are available in different sizes and shapes and from different vendors.
Bluetooth Smart
Bluetooth Low Energy is also known as Bluetooth Smart. Since Android 4.3 Jelly Bean, Android also supports Bluetooth Smart.
Android Smartphone Requirements:
- Android > 4.3
- Bluetooth Smart radio unit
The Android SDK has no built-in support for beacons. But there is a library from Radius Networks that can be used.
Beacon Advertisements
Beacons broadcast in regular intervals (e.g. something between 100ms and 1 second). They send out their ID.
The ID consists of three parts:
- UUID (organization or company)
- major (arbitrarily, e.g. specific chain store)
- minor (e.g. location in store)
Flow Control
First you have to define a Region. A region does not mean a geographically region, it’s rather a certain types of beacons you are interested in.
After defining a monitoring and ranging callback you can start monitoring.
Pseudo Code:
region = new Region("<someUUID>")
addMonitorCallback
->(didEnterRegion)
startRangingBeaconsInRegion
->(didExitRegion)
stopRangingBeaconsInRegion
addRangingCallback
->(didRangeBeaconsInRegion)
evalute beacon info
startMonitoring(region)
Coarse-grained Distance Estimations
The received signal strength indicator (RSSI) together with the Transmit Power can be used to measure the distance between transmitter and smartphone. The distance is not exactly measured; it’s more a coarse-grained estimation. Therefore often the proximity is divided into_Immediate_ (centimeters), Near (couple of meters) and Far (> 10 meters).
The library averages the distance measurements over 20 seconds in time, therefore you will note a lag, when the distance between beacons and smartphone changes. This might exactly be the behavior you want, since the distance estimations are coarse-grained and you are most likely interested in the information, which one of the beacons is the closest one.
Screencast
The following screencast shows in detail how to create a Beacon app for Android in less than 10 minutes from scratch.
Source Code
Finally here is the source code for this simple example.
package com.software7.beacon.app;
import android.os.RemoteException;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import org.altbeacon.beacon.*;
import java.util.Collection;
public class BeaconActivity extends ActionBarActivity implements BeaconConsumer {
public static final String TAG = "BeaconsEverywhere";
private BeaconManager beaconManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_beacon);
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
beaconManager.bind(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
beaconManager.unbind(this);
}
@Override
public void onBeaconServiceConnect() {
final Region region = new Region("myBeaons", Identifier.parse("<replaceBySomeUIID>"), null, null);
beaconManager.setMonitorNotifier(new MonitorNotifier() {
@Override
public void didEnterRegion(Region region) {
try {
Log.d(TAG, "didEnterRegion");
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void didExitRegion(Region region) {
try {
Log.d(TAG, "didExitRegion");
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void didDetermineStateForRegion(int i, Region region) {
}
});
beaconManager.setRangeNotifier(new RangeNotifier() {
@Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for(Beacon oneBeacon : beacons) {
Log.d(TAG, "distance: " + oneBeacon.getDistance() + " id:" + oneBeacon.getId1() + "/" + oneBeacon.getId2() + "/" + oneBeacon.getId3());
}
}
});
try {
beaconManager.startMonitoringBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_beacon, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Last Famous Words
I hope that gets you started with your beacon project.
If you found this helpful, share it!