iBeacons' background ranging with Altbeacon Library - android

I need to range beacons on the background using Altbeacons library(work properly on foreground mode)
On my android monitor the log never shows the message for the didRangeBeaconsInRegion method.
On the didEnterRegion, the messages are displayed correctly.
I tried the code below but no success, can any one guide me how to do it?
public class INBeaconApplication extends Application implements BootstrapNotifier, RangeNotifier {
private BeaconManager beaconManager;
private ArrayList<INBeacon> userBeaconArrayList;
private INBeaconUser inBeaconUser;
#Override
public void onCreate() {
super.onCreate();
Log.d("INBeacon", "Application created");
//BeaconManager and custom beaconParser layout
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setRegionStatePeristenceEnabled(false);
//Set the BeacomManager background between scan periods
long period = 1000 * 30; //equal to 30 seconds
beaconManager.setBackgroundBetweenScanPeriod(period);
// wake up the app when a beacon is seen
Region region = new Region(Utils.REGION_ID, Identifier
.parse(Utils.INBEACON_UUID), null, null);
new RegionBootstrap(this, region);
new BackgroundPowerSaver(this);
}
boolean checkPermissionForRange(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return getApplicationContext().checkSelfPermission(
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED;
}
return true;
}
#Override
public void didEnterRegion(Region region) {
Log.d("INBeacon", "didEnterRegion");
Utils.sendNotification(this, "Test");
if (checkPermissionForRange()) return;
Log.d("INBeacon", "permissions ok");
try {
beaconManager.startRangingBeaconsInRegion(region);
Log.d("INBeacon","startRanging");
} catch (RemoteException e) {
Log.e("INBeacon",e.getMessage());
}
}
#Override
public void didExitRegion(Region region) {
Log.d("INBeacon", "didExitRegion");
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> collection, Region region) {
Log.d("INBeacon", "didRangeBeaconsInRegion");
ArrayList<Beacon> newBeacons = new ArrayList<>(collection);
.............code to do what i need with the beacons.....
}

It looks like the code simply needs to call:
beaconManager.setRangeNotifier(this);

Related

AltBeacon on Android 8 slow on first run (app isn't responding)

Only for the first time lauching the app (after uninstall/install), after it starts scanning beacons, the message "App isn't responding" appears, only happening on Android 8 (Samsung A5 and J5 Prime). Removed everything from app leaving only the code for beacon detection, still happening.
Not sure if it's a problem with the library or the way I'm using it.
Calling BeaconConsumer(context) from my Application class.
public class BeaconConsumer implements BootstrapNotifier, org.altbeacon.beacon.BeaconConsumer {
BeaconManager beaconManager;
BeaconConsumer(Context applicationContext) {
beaconManager = BeaconManager.getInstanceForApplication(applicationContext);
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=6548,i:4-25,p:1-1"));
beaconManager.setEnableScheduledScanJobs(false);
beaconManager.setBackgroundBetweenScanPeriod(15300);
beaconManager.setBackgroundScanPeriod(1200);
beaconManager.setForegroundBetweenScanPeriod(10000);
beaconManager.setForegroundScanPeriod(1200);
beaconManager.bind(this);
beaconManager.setBackgroundMode(false);
BeaconManager.setDebug(true);
Region region = new Region("backgroundRegion", null, null, null);
RegionBootstrap regionBootstrap = new RegionBootstrap(this, region);
}
public void onBeaconServiceConnect() {
beaconManager.removeAllRangeNotifiers();
beaconManager.addRangeNotifier((beacons, region) -> {
Log.d("TAG", "didRangeBeaconsInRegion CALLED with size: " + beacons.size() + " on region: " + region);
Iterator<Beacon> iterator = beacons.iterator();
while (iterator.hasNext()) {
Beacon beacon = iterator.next();
Formatter formatter = new Formatter();
for (byte b : beacon.getId1().toByteArray()) {
formatter.format("%02x", b);
}
String payload = formatter.toString();
Log.d("TAG", "Processing payload: " + payload + " rssi: " + beacon.getRssi());
}
});
try {
beaconManager.startRangingBeaconsInRegion(myRegion);
} catch (RemoteException e) {
Log.d("TAG", "Exception starting ranging beacons in region");
}
}
public void didEnterRegion(Region region) {
try {
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
Log.d("TAG", "Can't start ranging");
}
Intent intent = new Intent(mContext, BeaconService.class);
intent.setAction("com.test.altbeacontest.beaconreference.Service.action.Scan");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mContext.startForegroundService(intent);
} else {
mContext.startService(intent);
}
mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("TAG", "ServiceConnection - connected");
}
#Override
public void onServiceDisconnected(ComponentName name) {
Log.d("TAG", "ServiceConnection - disconnected");
}
};
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
public void didExitRegion(Region region) {
Log.d("TAG", "I no longer see a beacon.");
insideRegion = false;
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
I suspect the problem has something to do with these operations used together in the same method:
beaconManager.bind(this);
...
RegionBootstrap regionBootstrap = new RegionBootstrap(this, region);
You really should not use these two together -- generally you use one or the other (binding to the BeaconManager) or using RegionBootstrap. The latter object itself binds internally.
I would remove: RegionBootstrap regionBootstrap = new RegionBootstrap(this, region); and instead add beaconManager.startMonitoringBeaconsInRegion(region); at the same time as you call beaconManager.startRangingBeaconsInRegion(myRegion);

AltBeacon sometime cannot range beacons

I want my app track with beacon all the time
it seem work fine been a while when it start tracking
after that, didRangeBeaconsInRegion() has an empty beacons collection
Here my code
public void onCreate() {
super.onCreate();
Log.d(TAG, "create");
beaconManager = BeaconManager.getInstanceForApplication(this);
try {
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setBackgroundScanPeriod(1101l);
beaconManager.setBackgroundBetweenScanPeriod(1101l);
beaconManager.setForegroundBetweenScanPeriod(1101l);
beaconManager.updateScanPeriods();
} catch (RemoteException e) { }
backgroundPowerSaver = new BackgroundPowerSaver(this);
startBeaconRanging();
}
public void startBeaconRanging() {
courseId = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).getString(getString(R.string.course_id), "");
Log.d(TAG, "startBeaconRanging on courseId = " + courseId);
if (!courseId.equals("")) {
syncBeaconWithFirebase(courseId);
endTime = CourseSQLiteManager.getColumnById(getApplicationContext(), courseId, COURSE_ENDTIME);
regionBootstrap = new RegionBootstrap(this, new Region("ranged region", null, null, null));
}
}
public void stopBeaconRanging() {
if (regionBootstrap != null) {
regionBootstrap.disable();
try {
Log.d(TAG, "end");
courseId = "";
beaconManager.stopRangingBeaconsInRegion(getRegion());
beaconManager.removeAllRangeNotifiers();
} catch (RemoteException e) { }
}
}
#Override
public void didEnterRegion(Region region) {
Log.d(TAG, "enter");
try {
Region r = getRegion();
if(r == null) {
regionBootstrap = new RegionBootstrap(this, new Region("ranged region", null, null, null));
Log.d(TAG, "null");
}
if(r != null) {
beaconManager.startRangingBeaconsInRegion(r);
beaconManager.addRangeNotifier(this);
}
} catch (RemoteException e) { }
}
#Override
public void didExitRegion(Region region) {
try {
if(getRegion() != null) beaconManager.stopRangingBeaconsInRegion(getRegion());
} catch (RemoteException e) { }
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if(beacons.size() > 0) {
Beacon beacon = beacons.iterator().next();
Log.d(TAG, beacon.getId2().toInt() + " " + beacon.getDistance() + " " + beacon.getRssi());
if(isAfterEndTime()) {
stopBeaconRanging();
}
}
}
EDIT: It happen like this both foreground and background. But If I kill my app and open it again, I can finds beacon but just a moment too.
EDIT2: isAfterEndTime is return false while it cannot finds any beacons. But the didExitRegion is triggered swap with didEnterRegion and it finds zero beacons
PS. I want to track with only one beacon at a time
PS.2 Sorry for my bad English. I'm not sure, are you get what I want to ask clearly or not?
A few things to check:
Make sure this code is not being triggered. I cannot see the definition of the method, but if it returns true, it will cause ranging to stop:
if(isAfterEndTime()) {
stopBeaconRanging();
}
Add a debug line in the didExitRegion to make sure it is not being called. (Since it also stops ranging.) As an aside, I don't think you need code that does this -- there is no efficiency cost to just continuing ranging if you aren't detecting beacons anyway.
Make sure this line of code is only executed once, as the RegionBootstrap is not designed to be created repeatedly:
regionBootstrap = new RegionBootstrap(this, new Region("ranged region", null, null, null));
Rather than repeatedly making a new RegionBootstrap object, just create one once at the beginning of your program. If you then want to change the monitored regions, you can do so with beaconManager.stopMonitoringBeaconsInRegion(region1); and beaconManager.startMonitoringBeaconsInRegion(region2);

PendingResult<PlaceLikelihoodBuffer> is getting executed for the second time

I am trying to make an application where user current place will be messaged to predefined number. I have implemented ShakeDetector library. Everything is working fine but I am getting the place name for the second time when I am shaking the device. [Please see the screenshots]
I put a debug point on the lines on PendingResult part.
For the first time the "for loop" is not executing but when I am shaking it for the second time the for loop is executing and I am getting the places. Whats wrong? Does PendingResult work as asynctask in android?
PS: I faced the similar problem while I was working with Google Fit API.the PendingResult was getting executed when I am returning to previous activity by pressing back button.I resolved the issue by creating different fragments and providing single GoogleApiClient to each of them.But as you can guess there is no scope of this here. What should I do plz help.
here is my code of the PhoneService.java where everything is happening.
public class PhoneService extends Service implements GoogleApiClient.OnConnectionFailedListener,GoogleApiClient.ConnectionCallbacks {
GoogleApiClient googleApiClient;
String place="";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
ShakeDetector.create(this, new ShakeDetector.OnShakeListener() {
#Override
public void OnShake() {
try{
Toast.makeText(PhoneService.this,"Shake Detected",Toast.LENGTH_SHORT).show();
buildApiClient();
}catch (SecurityException e){
}
}
});
ShakeDetector.updateConfiguration(3f, 4);
ShakeDetector.start();
Toast.makeText(this,"Service started",Toast.LENGTH_SHORT).show();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
ShakeDetector.stop();
}
public void buildApiClient(){
googleApiClient= new GoogleApiClient
.Builder(this)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.addConnectionCallbacks(PhoneService.this)
.addOnConnectionFailedListener(PhoneService.this)
.build();
googleApiClient.connect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Toast.makeText(PhoneService.this,"Connected",Toast.LENGTH_SHORT).show();
try{
if(googleApiClient.isConnected()){
PendingResult<PlaceLikelihoodBuffer> result = Places.PlaceDetectionApi
.getCurrentPlace(googleApiClient, null);
result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
#Override
public void onResult(PlaceLikelihoodBuffer likelyPlaces) {
for (PlaceLikelihood placeLikelihood : likelyPlaces) {
place=placeLikelihood.getPlace().getName()+"";
Log.d("PLACE",place);
}
likelyPlaces.release();
try{
SmsManager smsManager=SmsManager.getDefault();
smsManager.sendTextMessage("7098027655",null,"I am here at "+place+".Please pick me up.",null,null);
}catch (SecurityException e){
}
}
});
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:7098027655"));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(callIntent);
}
}catch (SecurityException e){
}
}
#Override
public void onConnectionSuspended(int i) {
Toast.makeText(PhoneService.this,"Connection Suspended",Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Toast.makeText(PhoneService.this,"Connection Failed",Toast.LENGTH_SHORT).show();
}
}
You're creating and connecting a brand new GoogleApiClient every time the user shakes the device. You might have more luck creating and connecting the client once in the service's onCreate() method.

Android Beacon Library - BLE beacons detecting is not working

I am trying to detecting beacons with Android Beacon Library in Android. I created a service which is running in background and detecting beacons.
The problem is that app is not detecting beacons when bluetooth is turned off. But if I turn on bluetooth is working properly. There is a really weird thing as well. If I turn off bluetooth again while app is running, it still continue detecting. It means that BLE detecting is working but only if I turn on bluetooth and turn it off again.
How can I enable BLE detecting? There is my implementation below. Do I miss something?
Beacon Service class
public class BeaconDiscoverer extends Service implements BeaconConsumer {
private static final String TAG = BeaconDiscoverer.class.getSimpleName();
private static BeaconManager beaconManager;
private static Region region;
private BackgroundPowerSaver backgroundPowerSaver;
public BeaconDiscoverer() {
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
region = new Region("myRangingUniqueId", null, null, null);
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"));
configureBatterySaverMode();
beaconManager.bind(this);
}
#Override
public void onDestroy() {
beaconManager.unbind(this);
super.onDestroy();
}
private void configureBatterySaverMode() {
BeaconManager.setAndroidLScanningDisabled(true);
backgroundPowerSaver = new BackgroundPowerSaver(getApplicationContext());
// set the duration of the scan to be 5 seconds
beaconManager.setBackgroundScanPeriod(Utility.convertToMilliseconds(2));
// set the time between each scan to be 1 min (60 seconds)
beaconManager.setBackgroundBetweenScanPeriod(Utility.convertToMilliseconds(25));
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "BeaconDiscoverer started up");
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onBeaconServiceConnect() {
Log.d(TAG, "onBeaconServiceConnect");
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
Beacon firstBeacon = beacons.iterator().next();
Log.i(TAG, "Beacon detected: " + firstBeacon.getDistance() + " m. - " + firstBeacon.getBluetoothAddress());
}
}
});
startRanging();
}
public void stopRanging() {
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void startRanging() {
if (User.currentUser() == null)
return;
try {
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
Application class
public class App extends Application {
private static final String TAG = App.class.getSimpleName();
#Override
public void onCreate() {
super.onCreate();
startService(new Intent(this, BeaconDiscoverer.class));
}
}
Simple answer: you must have Bluetooth enabled to detect beacons with the library. Beacons use Bluetooth LE to advertise their presence, and the Bluetooth radio must be on to hear the signals.
I cannot explain why you continue to detect beacons after turning off Bluetooth. One possibility is that you just see them from memory cache for the library's brief scan cycle period before they disappear. Another possibility is that the Android device is saying Bluetooth is off when you switch it off, but it is not really off.
The typical approach is to detect if Bluetooth is off when the app is launched, and prompt the user to turn it on. There is sample code in the Reference Application that does this here.
private void registerBoradcastReceiver() {
IntentFilter stateChangeFilter = new IntentFilter(
BluetoothAdapter.ACTION_STATE_CHANGED);
IntentFilter connectedFilter = new IntentFilter(
BluetoothDevice.ACTION_ACL_CONNECTED);
//IntentFilter connectedFilter = new IntentFilter(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
IntentFilter disConnectedFilter = new IntentFilter(
BluetoothDevice.ACTION_ACL_DISCONNECTED);
registerReceiver(stateChangeReceiver, stateChangeFilter);
registerReceiver(stateChangeReceiver, connectedFilter);
registerReceiver(stateChangeReceiver, disConnectedFilter);
}
private BroadcastReceiver stateChangeReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_ACL_CONNECTED == action) {
startService;
}
if (BluetoothDevice.ACTION_ACL_DISCONNECTED == action) {
stopService;
}
if (BluetoothAdapter.ACTION_STATE_CHANGED == action) {
}
}
};

How to parse iBeacon identifiers from Altbeacon's bootstrap and start application with them?

I'm trying to get the bootstrap to gather id2 and id3 from iBeacons and start an activity with them. The problem is that the application wouldn't start from the intent and I keep seeing D/BeaconService﹕ Calling ranging callback D/Callback﹕ attempting callback via intent: ComponentInfo{com.rp_ds.chequeplease/org.altbeacon.beacon.BeaconIntentProcessor}
Below is my code:
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "App started up");
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.setDebug(true);
// Add AltBeacons Parser for iBeacon
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
// wake up the app when any beacon is seen (you can specify specific id filers in the parameters below)
region = new Region("com.rp_ds.chequeplease.bootstrapRegion", Identifier.parse("F8EFB5C2-9FFF-47AE-8C8D-D23C417882D1"), null, null);
regionBootstrap = new RegionBootstrap(this, region);
backgroundPowerSaver = new BackgroundPowerSaver(this);
_appPrefs = new AppPreferences(this);
}
#Override
public void didDetermineStateForRegion(int arg0, Region arg1) {
// Don't care
}
#Override
public void didEnterRegion(Region arg0) {
Log.d(TAG, "Got a didEnterRegion call");
try {
beaconManager.startRangingBeaconsInRegion(arg0);
} catch (RemoteException e) {
e.printStackTrace();
}
// This call to disable will make it so the activity below only gets launched the first time a beacon is seen (until the next time the app is launched)
// if you want the Activity to launch every single time beacons come into view, remove this call.
}
#Override
public void didExitRegion(Region arg0) {
// Don't care
}
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
Log.d(TAG, "Got a didRangeBeaconsInRegion call");
for(Beacon beacon:beacons) {
if(null!=beacon.getId2()&&null!=beacon.getId3()) {
Intent intent = new Intent(this, MainActivity.class);
_appPrefs.setRestaurantID(beacon.getId2().toInt());
_appPrefs.setTableNumber(beacon.getId3().toInt());
// IMPORTANT: in the AndroidManifest.xml definition of this activity, you must set android:launchMode="singleInstance" or you will get two instances
// created when a user launches the activity manually and it gets launched from here.
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
Log.i(TAG,"Application started");
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
}
I do get a didEnterRegion call but there wasn't a didRangeBeaconsInRegion call. The beacons are also recognized.
D/BeaconParser﹕ This is a recognized beacon advertisement -- 0215 seen
D/BeaconIntentProcessor﹕ got an intent to process
D/RangingData﹕ parsing RangingData
D/RangingData﹕ parsing RangingData
D/BeaconIntentProcessor﹕ got ranging data
D/BeaconIntentProcessor﹕ but ranging notifier is null, so we're dropping it.
The range notifier needs to be set like this:
#Override
public void didEnterRegion(Region arg0) {
Log.d(TAG, "Got a didEnterRegion call");
try {
beaconManager.startRangingBeaconsInRegion(arg0);
beaconManager.setRangeNotifier(this);
} catch (RemoteException e) {
e.printStackTrace();
}
}
Make sure the containing class implements the RangeNotifier interface.

Categories

Resources