{"id":25272,"date":"2015-08-06T16:22:30","date_gmt":"2015-08-06T10:52:30","guid":{"rendered":"http:\/\/www.tothenew.com\/blog\/?p=25272"},"modified":"2015-10-13T14:34:53","modified_gmt":"2015-10-13T09:04:53","slug":"beacon-implementation-in-android","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/beacon-implementation-in-android\/","title":{"rendered":"Beacon Implementation in Android"},"content":{"rendered":"<p>In <a title=\"Beacon \u2013 An Introduction\" href=\"http:\/\/www.tothenew.com\/blog\/beacon_introduction\/\">our previous post<\/a> we have given a overview of what Beacon is, so here we are with its practical implementation.<\/p>\n<p>There are two applications required to create Beacon experience.<\/p>\n<p>1. Transmitter<br \/>\n2. Receiver<\/p>\n<p>For Transmitter \u2013<\/p>\n<p>1. Bluetooth should be on<br \/>\ngetSystemService(Context.BLUETOOTH_SERVICE)<\/p>\n<p>2. BLE supported device<br \/>\nhasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE))<\/p>\n<p>&lt;uses-permission android:name=&#8221;android.permission.BLUETOOTH&#8221; \/&gt;<br \/>\n&lt;uses-permission android:name=&#8221;android.permission.BLUETOOTH_ADMIN&#8221; \/&gt;<\/p>\n<p>If device supports BLE, then the Beacon Transmitter transmits the advertisements like this,<\/p>\n<p>\/**<br \/>\n* Simulates a new beacon every 10 seconds until it runs out of new ones to add.<br \/>\n*\/<\/p>\n<p>[code language=&#8221;java&#8221;]<br \/>\nBeacon beacon = new Beacon.Builder()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .setId1(\u201c2f234454-cf6d-4a0f-adf2-f4911ba9ffa6\u201d)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .setId2(\u201c1\u201d)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .setId3(\u201c2\u201d)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .setManufacturer(0x0118)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .setTxPower(-59)<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .setDataFields(Arrays.asList(new Long[] {0l}))<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .build();<br \/>\nBeaconParser beaconParser = new BeaconParser()<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .setBeaconLayout(&quot;m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25&quot;);<br \/>\nBeaconTransmitter beaconTransmitter = new BeaconTransmitter(getApplicationContext(), beaconParser);<br \/>\nbeaconTransmitter.startAdvertising(beacon);<br \/>\nscheduleTaskExecutor= Executors.newScheduledThreadPool(5);<br \/>\n\/\/ This schedules an beacon to appear every 10 seconds:<br \/>\nscheduleTaskExecutor.scheduleAtFixedRate(new Runnable(){<br \/>\n         public void run() {<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0              try{<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0                  \/\/putting a single beacon back into the beacons list.<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0                  if (finalBeacons.size() &gt; beacons.size())<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0                  beacons.add(finalBeacons.get(beacons.size()));<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0                   \u00a0else<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0                  scheduleTaskExecutor.shutdown();<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0          }catch(Exception e){<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0           e.printStackTrace();<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0        }<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0      }<br \/>\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0    }, 0, 10, TimeUnit.SECONDS);<br \/>\n\u00a0\u00a0 \u00a0   }<br \/>\n }<br \/>\n[\/code]<\/p>\n<p>Beacon Advertisement Receiver<\/p>\n<p>Two classes are main in this receiver<br \/>\n1. Beacon Parser<br \/>\n2. Beacon Manager<\/p>\n<p>Beacon Parser \u2013 It parses the advertised data into relevant information.<\/p>\n<p>&nbsp;<\/p>\n<p>[code language=&#8221;java&#8221;]<br \/>\n@TargetApi(5)<br \/>\nprotected Beacon fromScanData(byte[] scanData, int rssi, BluetoothDevice device, Beacon beacon) {<br \/>\nint startByte = 2;<br \/>\nboolean patternFound = false;<br \/>\nbyte[] typeCodeBytes = longToByteArray(getMatchingBeaconTypeCode(), mMatchingBeaconTypeCodeEndOffset-mMatchingBeaconTypeCodeStartOffset+1);<\/p>\n<p>while (startByte &lt;= 5) {<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 if (byteArraysMatch(scanData, startByte+mMatchingBeaconTypeCodeStartOffset, typeCodeBytes, 0)) {<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 patternFound = true;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 break;<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 }<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0 startByte++;<br \/>\n}<\/p>\n<p>if (patternFound == false) {<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 \/\/ This is not an beacon<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 BeaconManager.logDebug(TAG, &quot;This is not a matching Beacon advertisement.\u00a0 (Was expecting &quot;+byteArrayToString(typeCodeBytes)+&quot;.\u00a0 The bytes I see are: &quot;+bytesToHex(scanData));<br \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 return null;<br \/>\n}<br \/>\nelse {<br \/>\n\/\/BeaconManager.logDebug(TAG, &quot;This is a recognized beacon advertisement &#8212; &quot;+String.format(&quot;%04x&quot;, getMatchingBeaconTypeCode())+&quot; seen&quot;);<br \/>\nLog.e(&quot;rec beacon**&quot;, &quot;This is a recognized beacon advertisement &#8212; &quot;+String.format(&quot;%04x&quot;, getMatchingBeaconTypeCode())+&quot; seen&quot;);<br \/>\n}<\/p>\n<p>ArrayList&lt;Identifier&gt; identifiers = new ArrayList&lt;Identifier&gt;();<br \/>\nfor (int i = 0; i &lt; mIdentifierEndOffsets.size(); i++) {<br \/>\n\u00a0\u00a0\u00a0 String idString = byteArrayToFormattedString(scanData, mIdentifierStartOffsets.get(i)+startByte, mIdentifierEndOffsets.get(i)+startByte, mIdentifierLittleEndianFlags.get(i));<br \/>\n\u00a0\u00a0\u00a0 Log.e(&quot;idString&quot;,idString);<br \/>\n\u00a0\u00a0\u00a0 identifiers.add(Identifier.parse(idString));<br \/>\n}<br \/>\nArrayList&lt;Long&gt; dataFields = new ArrayList&lt;Long&gt;();<br \/>\nfor (int i = 0; i &lt; mDataEndOffsets.size(); i++) {<br \/>\n\u00a0\u00a0\u00a0\u00a0 String dataString = byteArrayToFormattedString(scanData, mDataStartOffsets.get(i)+startByte, mDataEndOffsets.get(i)+startByte, mDataLittleEndianFlags.get(i));<br \/>\n\u00a0\u00a0\u00a0\u00a0 dataFields.add(Long.parseLong(dataString));<br \/>\n\u00a0\u00a0\u00a0\u00a0 BeaconManager.logDebug(TAG, &quot;parsing found data field &quot;+i);<br \/>\n\u00a0\u00a0\u00a0\u00a0 \/\/ TODO: error handling needed here on the parse<br \/>\n}<\/p>\n<p>int txPower = 0;<br \/>\nString powerString = byteArrayToFormattedString(scanData, mPowerStartOffset+startByte, mPowerEndOffset+startByte, false);<br \/>\ntxPower = Integer.parseInt(powerString);<\/p>\n<p>\/\/ make sure it is a signed integer<br \/>\nif (txPower &gt; 127) {<br \/>\n\u00a0\u00a0\u00a0 txPower -= 256;<br \/>\n}<br \/>\nLog.e(&quot;txPower data&quot;,txPower+&quot;&quot;);<br \/>\n\u00a0\u00a0\u00a0\u00a0 \u00a0<br \/>\n\/\/ TODO: error handling needed on the parse<\/p>\n<p>int beaconTypeCode = 0;<br \/>\nString beaconTypeString = byteArrayToFormattedString(scanData, mMatchingBeaconTypeCodeStartOffset+startByte, mMatchingBeaconTypeCodeEndOffset+startByte, false);<br \/>\nbeaconTypeCode = Integer.parseInt(beaconTypeString);<br \/>\n\/\/ TODO: error handling needed on the parse<\/p>\n<p>int manufacturer = 0;<br \/>\nString manufacturerString = byteArrayToFormattedString(scanData, startByte, startByte+1, true);<br \/>\nmanufacturer = Integer.parseInt(manufacturerString);<\/p>\n<p>String macAddress = null;<br \/>\nString name = null;<br \/>\nif (device != null) {<br \/>\n\u00a0\u00a0\u00a0 macAddress = device.getAddress();<br \/>\n\u00a0\u00a0\u00a0 name = device.getName();<br \/>\n}<br \/>\nbeacon.mIdentifiers = identifiers;<br \/>\nbeacon.mDataFields = dataFields;<br \/>\nbeacon.mTxPower = txPower;<br \/>\nbeacon.mRssi = rssi;<br \/>\nbeacon.mBeaconTypeCode = beaconTypeCode;<br \/>\nbeacon.mBluetoothAddress = macAddress;<br \/>\nbeacon.mBluetoothName= name;<br \/>\nbeacon.mManufacturer = manufacturer;<br \/>\nreturn beacon;<br \/>\n}<\/p>\n<p>[\/code]<\/p>\n<p>Beacon Manager \u2013 It specifies the time interval for scanning Beacons in range.<\/p>\n<p>public static final long DEFAULT_FOREGROUND_SCAN_PERIOD = 1000;<br \/>\n\/**<br \/>\n* The default duration in milliseconds spent not scanning between each bluetooth scan\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 cycle<br \/>\n*\/<\/p>\n<p>&nbsp;<\/p>\n<p>[code language=&#8221;java&#8221;]<br \/>\npublic static final long DEFAULT_FOREGROUND_BETWEEN_SCAN_PERIOD = 2*60*1000;\u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ 2 minutes in foreground<\/p>\n<p>[\/code]<\/p>\n<p>\/**<br \/>\n* The default duration in milliseconds of the bluetooth scan cycle when no \u00a0\u00a0 \u00a0ranging\/monitoring clients<br \/>\n*\/\u00a0\u00a0 \u00a0are in the foreground<\/p>\n<p>[code language=&#8221;java&#8221;]<br \/>\npublic static final long DEFAULT_BACKGROUND_SCAN_PERIOD = 10000;<\/p>\n<p>[\/code]<\/p>\n<p>\/**<br \/>\n* The default duration in milliseconds spent not scanning between each bluetooth scan \u00a0\u00a0 \u00a0cycle when no\u00a0\u00a0 *\/\u00a0\u00a0 \u00a0ranging\/monitoring clients are in the foreground<\/p>\n<p>[code language=&#8221;java&#8221;]<br \/>\npublic static final long DEFAULT_BACKGROUND_BETWEEN_SCAN_PERIOD = 2*60*1000;\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\/\/ 2 minutes in background<\/p>\n<p>[\/code]<\/p>\n<p><a title=\"Beacons - Building Proximity Solutions for Brands | TO THE NEW\" href=\"http:\/\/insights.tothenew.com\/mobility-beacons-proximity-solutions\" target=\"_blank\"><img decoding=\"async\" loading=\"lazy\" class=\"alignnone size-full wp-image-26908\" src=\"\/blog\/wp-ttn-blog\/uploads\/2015\/08\/Beacon-whitepaper-dwnload-banner.png\" alt=\"Beacon whitepaper dwnload banner\" width=\"799\" height=\"201\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In our previous post we have given a overview of what Beacon is, so here we are with its practical implementation. There are two applications required to create Beacon experience. 1. Transmitter 2. Receiver For Transmitter \u2013 1. Bluetooth should be on getSystemService(Context.BLUETOOTH_SERVICE) 2. BLE supported device hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) &lt;uses-permission android:name=&#8221;android.permission.BLUETOOTH&#8221; \/&gt; &lt;uses-permission android:name=&#8221;android.permission.BLUETOOTH_ADMIN&#8221; \/&gt; If [&hellip;]<\/p>\n","protected":false},"author":164,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":0},"categories":[518,446,1772,1],"tags":[2184],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/25272"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/164"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=25272"}],"version-history":[{"count":0,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/25272\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=25272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=25272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=25272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}