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

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);

Related

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);

iBeacons' background ranging with Altbeacon Library

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);

Starting app in background when beaconmanager is bound

I have trouble with showing my app on region entered, I followed the sample here.
It works when I don't bind the BeaconManager to my Activty, but when I do, I get the logs from the Activity not from the Application and the app doesn't show up although it's not visible.
So the question is, can I use a class extends Application implements BootstrapNotifier for starting the app in background and a class extends AppCompatActivity implements BeaconConsumer to handle monitoring/ranging or do I need to handle everything in the application class because binding it in the activity fails the background launch?
(Sorry for the bad code block, I just can't handle this stackoverflow code thing correctly)
public class BeaconActivity extends AppCompatActivity implements BeaconConsumer {
protected final String TAG = "BeaconActivity";
private BeaconManager beaconManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate()");
setContentView(R.layout.activity_beacon);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
RangedBeacon.setSampleExpirationMilliseconds(8000);
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.bind(this);
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "Unbind Beaconmanager");
beaconManager.unbind(this);
}
#Override
public void onBeaconServiceConnect() {
beaconManager.setMonitorNotifier(new MonitorNotifier() {
#Override
public void didEnterRegion(final Region region) {
Log.d(TAG, "Enter Region identifier: " + region.getId1() + ", " + region.getId2() + ", " + region.getId3());
}
#Override
public void didExitRegion(final Region region) {
Log.d(TAG, "Exit Region identifier: " + region.getId1() + ", " + region.getId2() + ", " + region.getId3());
}
#Override
public void didDetermineStateForRegion(int state, Region region) {
}
});
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
for (final Beacon beacon : beacons) {
final String distance = new DecimalFormat("##.######").format(beacon.getDistance());
Log.d(TAG, "Distance: " + distance + ". This beacon has identifiers:" + beacon.getId1() + ", " + beacon.getId2() + ", " + beacon.getId3());
}
}
});
try {
Region region = new Region("all", null, null, null);
beaconManager.startMonitoringBeaconsInRegion(all);
beaconManager.startRangingBeaconsInRegion(all);
} catch (RemoteException e) {
}
}
}
public class BeaconApplication extends Application implements BootstrapNotifier {
private static final String TAG = "BeaconApplication";
private RegionBootstrap regionBootstrap;
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "App started up");
BeaconManager 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"));
Region all = new Region("all", null, null, null);
regionBootstrap = new RegionBootstrap(this, all);
}
#Override
public void didEnterRegion(Region region) {
Log.d(TAG, "Enter region " + region.getUniqueId());
// regionBootstrap.disable();
Intent intent = new Intent(this, BeaconActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
}
#Override
public void didExitRegion(Region region) {
Log.d(TAG, "Exit region " + region.getUniqueId());
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
}
Edit:
I think I might just screwed up a little. Explained here the app only launches if killed (not in task switcher anymore). If it's available in task switcher it just handles the incoming events in the background, that's why I get the activity logs.
The problem is that you can only have one monitorNotifier for your application. The RegionBootstrap class sets one internally, and uses it to get callbacks to your Application class.
The code shown above changes the monitorNotifier here:
public void onBeaconServiceConnect() {
beaconManager.setMonitorNotifier(new MonitorNotifier() {
...
After that line executes, the RegionBootstrap won't get any more callbacks on entry/exit events, and nor will the Application class. So the problem isn't the bind() call, it's the setMonitorNotifier call.
The library does not allow multiple monitorNotifiers, so if you want to keep using the RegionBootstrap you have to refactor your code so that you get all of the entry/exit events in your Application class and somehow pass them off to your Activity.

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