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);
Related
I am trying to build an app where the strength of the nearest beacon is detected (by the signal strength) and the corresponding API must be called (with the beacon ID as a parameter). The app asks for location the first time and runs very well (detects the nearest beacon). But after I close the app and reopen it, the beacon ID will be empty always (string2 variable is being set with beacon ID). Why is it running the first time and not subsequent times?
Whenever I clear the data of the app, the app asks for location and runs fine. I have coded the entire segment again three times and yet I encounter the same problem.
I have tried to trace the flow through log statements. I observed that onBeaconServiceConnect() method isn't executing the second time (unless the app's data is cleared).
AsyncTask:
public class Navigate extends AsyncTask<String, String, String> {
protected String doInBackground(String... strings) {
//REST Query
String cs, ps = null;
//Here bid is a field and it will be set to Beacon ID of the nearest beacon.
while (!bid.equals(strings[1])) {
try {
imageURL=callAPI("bid1","bid3");
Log.e("BeaconID", bid); //The default value of bid will be printed and not the beacon ID.
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}
Log.e("Debug", "Step3");
return "none";
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
Toast.makeText(getApplicationContext(), "onProgressUpdate", Toast.LENGTH_SHORT).show();
mNetworkImageView = (NetworkImageView) findViewById(R.id.mapImage);
mImageLoader = CustomVolleyRequestQueue.getInstance(getApplicationContext()).getImageLoader();
mImageLoader.get(values[0], ImageLoader.getImageListener(mNetworkImageView, R.mipmap.ic_launcher_round, android.R.drawable.ic_menu_report_image));
Log.e("Image Published", values[0]);
mNetworkImageView.setImageUrl(values[0], mImageLoader);
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
progressDialog.dismiss();
tv.setText(s);
}
}
OnBeaconServiceConnect:-
public void onBeaconServiceConnect() {
//Constructing a new Region object to be used for Ranging or Monitoring
region = new Region("myBeaons", Identifier.parse("23542266-18D1-4FE4-B4A1-23F8195B9D39"), null, null);
//Specifies a class that should be called each time the BeaconService sees or stops seeing a Region of beacons.
beaconManager.addMonitorNotifier(new MonitorNotifier() {
/*
This override method is runned when some beacon will come under the range of device.
*/
#Override
public void didEnterRegion(Region region) {
System.out.println("ENTER ------------------->");
try {
//Tells the BeaconService to start looking for beacons that match the passed Region object
// , and providing updates on the estimated mDistance every seconds while beacons in the Region
// are visible.
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
Log.e("Debug", "Step10");
}
/*
This override method is runned when beacon that comes in the range of device
,now been exited from the range of device.
*/
#Override
public void didExitRegion(Region region) {
System.out.println("EXIT----------------------->");
try {
//Tells the BeaconService to stop looking for beacons
// that match the passed Region object and providing mDistance
// information for them.
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
Log.e("Debug", "Step11");
}
/*
This override method will Determine the state for the device , whether device is in range
of beacon or not , if yes then i = 1 and if no then i = 0
*/
#Override
public void didDetermineStateForRegion(int state, Region region) {
System.out.println("I have just switched from seeing/not seeing beacons: " + state);
}
});
//Specifies a class that should be called each time the BeaconService gets ranging data,
// which is nominally once per second when beacons are detected.
beaconManager.addRangeNotifier(new RangeNotifier() {
/*
This Override method tells us all the collections of beacons and their details that
are detected within the range by device
*/
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
// Checking if the Beacon inside the collection (ex. list) is there or not
// if Beacon is detected then size of collection is > 0
if (beacons.size() > 0) {
final ArrayList<ArrayList<String>> arrayList = new ArrayList<ArrayList<String>>();
BeaconManager.setRssiFilterImplClass(ArmaRssiFilter.class);
// Iterating through all Beacons from Collection of Beacons
ArrayList<Integer> arr = new ArrayList<Integer>();
int count = 0;
for (Beacon b : beacons) {
//RSSI
count += 1;
System.out.println(b.getBluetoothAddress()+" : "+b.getBluetoothName());
System.out.println("Count : " + count);
Integer rssi = Integer.valueOf(b.getRssi());
arr.add(rssi);
Integer maxRssi = Collections.max(arr);
for(Beacon b1 : beacons){
if(b1.getRssi() == maxRssi)
{
start = b1.getId1().toString();
maxid = start;
Log.e("Debug", "Step12");
System.out.println("uuid :"+func());
}
}
}
}
}
});
try {
//Tells the BeaconService to start looking for beacons that match the passed Region object.
beaconManager.startMonitoringBeaconsInRegion(region);
} catch (RemoteException e) {
}
}
#Override
public void onDestroy() {
super.onDestroy();
//Unbinds an Android Activity or Service to the BeaconService to avoid leak.
beaconManager.unbind(this);
finish();
}
The bid is set on the first go. Whenever I exit the app and reopen it again, the bid will not change at all. I have to clear the data of the app and re-run it to work properly.
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);
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);
I am using Robolectric to test my Android app. The app uses the AndroidBeaconLibrary.
When i use
Activity activity = Robolectric.setupActivity(MainActivity.class);
as a simple test, I get an error in the onBeaconServiceConnect() method:
#Override
public void onBeaconServiceConnect() {
beaconManager.setRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
if (beacons.size() > 0) {
final double distance = beacons.iterator().next().getDistance();
Log.i("X", "The beacon is about " + distance + " meters away.");
if (distance > 1.8 && !mAlertShown) {
mAlertShown = true;
alertOpen();
} else if (distance < 1) {
mAlertShown = false;
Toast.makeText(MainActivity.this, "alert is now reset", Toast.LENGTH_SHORT).show();
}
}
}
});
try {
Identifier i = Identifier.parse("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
Identifier i2 = Identifier.parse("xxxx");
beaconManager.startRangingBeaconsInRegion(new Region("rangingUniqueId", i, i2, null));
} catch (RemoteException e) {
}
}
The method fails after calling beaconManager.startRangingBeaconsInRegion(new Region("rangingUniqueId", i, i2, null)); at this.serviceMessenger.send(msg); in the BeaconManager.class. with a NullPointerException.
When I deploy the app on my phone, everything works just fine.
I can't comment so im going to write it here as answer but this sound like in this.serviceMessenger.send(msg); the value of msg is NULL and that is why you get the exception.
public void startRangingBeaconsInRegion(Region region) throws RemoteException {
Message msg = Message.obtain(null, IBeaconService.MSG_START_RANGING, 0, 0);
StartRMData obj = new StartRMData(new RegionData(region), rangingCallbackAction());
msg.obj = obj;
msg.replyTo = rangingCallback;
if(msg != null){
serviceMessenger.send(msg);
}
}
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.