AltBeacon Not Finding Beacons - altbeacon

I am trying to implement the AltBeacon library to range beacons similarly to the way iOS does. However I am having trouble getting my app to recognize any beacons.
Here is my code:
onCreate:
beaconManager = BeaconManager.getInstanceForApplication(this)
beaconManager.bind(this)
var region = Region(route.route.uuid, null, null, null)
beaconManager.startMonitoringBeaconsInRegion(region)
onBeaconServiceConnect
override fun onBeaconServiceConnect() {
beaconManager.removeAllRangeNotifiers()
beaconManager.addRangeNotifier(object : RangeNotifier {
override fun didRangeBeaconsInRegion(
beacons: Collection<Beacon>,
region: Region?
) {
if (beacons.size > 0) {
println("I see ${beacons.size} beacons")
log += "The first beacon I see is about " + beacons.iterator().next().getDistance()
.toString() + " meters away."
log += "I see ${beacons.size} beacons.\n"
debugLog()
}
else
{
println("I see 0 beacons")
log += "I see 0 beacons\n"
debugLog()
}
}
})
try {
beaconManager.startRangingBeaconsInRegion(Region("myRangingUniqueId", null, null, null))
} catch (e: RemoteException) {
}
}
Am I missing an element for it to range standard iBeacon BLE packets? Any help is appreciated.
Thanks

The most likely reasons are:
Your route.route.uuid does not match the UUID of the transmitter.
You didn't set the BeaconLayout if you are using iBeacon. (By default, the library only detects AltBeacon)
You didn't obtain the required location permission from the user to be able to look for bluetooth beacons, causing the operating system to block detections.
I wrote a checklist to help troubleshoot problems like this.

Related

How to restart the scan in Altbeacon library?

I have referred to this question already : Stopping and restarting foreground service scanning with altbeacon
My requirement is to restart the beacon scan depending on API response containing scanTime and waitTime. I would have started a scan with default config and once i receive API response from server i need to restart the scan with new config. So this is the code i have. Is this valid to just stop and then start the scan again? Will this have any adverse effect?
public void reconnect(int scanTimeInMills, int waitTimeInMillis) {
try {
if (beaconManager != null) {
beaconManager.stopRangingBeaconsInRegion(ALL_REGION);
beaconManager.unbind(this);
}
beaconManager = null;
beaconManager = BeaconManager.getInstanceForApplication(MyApplication.getInstance());
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setForegroundScanPeriod(scanTimeInMills);
beaconManager.setBackgroundScanPeriod(scanTimeInMills);
beaconManager.setBackgroundBetweenScanPeriod(waitTimeInMillis);
beaconManager.setForegroundBetweenScanPeriod(waitTimeInMillis);
if (!beaconManager.isBound(this)) {
String channelName = "App Notification Service";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel chan = new NotificationChannel(
String.valueOf(Constant.APP_CLOCKIN_NOTIIFICATION_ID), channelName,
NotificationManager.IMPORTANCE_DEFAULT);
chan.setLightColor(Color.BLUE);
chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) WrkspotApplication.getInstance()
.getSystemService(Context.NOTIFICATION_SERVICE);
assert manager != null;
manager.createNotificationChannel(chan);
}
Intent intent = new Intent(MyApplication.getInstance(), HomeScreenActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
MyApplication.getInstance(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder notificationBuilder = new Builder(
MyApplication.getInstance())
.setLargeIcon(BitmapFactory
.decodeResource(MyApplication.getInstance().getResources(),
R.mipmap.ic_launcher))
.setSmallIcon(R.drawable.ic_logo_notification)
.setContentTitle(getApplicationContext().getString(R.string.app_name))
.setContentText(
getApplicationContext().getString(R.string.you_are_clocked_in))
.setStyle(new BigTextStyle().bigText(
getApplicationContext().getString(R.string.you_are_clocked_in)))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setChannelId(String.valueOf(Constant.APP_CLOCKIN_NOTIIFICATION_ID));
beaconManager.enableForegroundServiceScanning(notificationBuilder.build(),
Constant.APP_CLOCKIN_NOTIIFICATION_ID);
beaconManager.bind(this);
}
} catch (Exception e) {
Log.e(getClass().getSimpleName(), String.valueOf(e.getMessage()));
}
}
This really does not require all that code. Just use:
beaconManager.setForegroundScanPeriod(scanTimeInMills);
beaconManager.setForegroundBetweenScanPeriod(waitTimeInMillis);
beaconManager.setBackgroundMode(false);
beaconManager.updateScanPeriods();
You do not need to set both foreground and background scan periods. Just do not use BackgroundPowerSaver, and you can leave it in foreground mode all the time.
All the complex logic binding and unbinding shown in the question can cause trouble because it starts and stops the scanning process. This is an asynchronous operation, and it can lead to race conditions. Best to keep it simple.

Flutter Blue Writing Automatically

I have used Flutter Blue for a college work, where I need to create an application to fetch and pass information to an equipment. The passing of this data must be automatic, as in any application (after all the end user should not look for the services and characteristics necessary to carry out the process). The problem is that I am not being able to perform the data passing soon after connecting with the device.
I'm using the App example I downloaded at https://github.com/pauldemarco/flutter_blue, so the basic idea is that as soon as I connect to my bluetooth device I send a message to a certain device. There is already an answered question that has the interest of setting notifications when connecting at Flutter Blue Setting Notifications
I followed the same example but instead of using _setNotification (c) I used the _writeCharacteristic (c), but it does not work.
_connect(BluetoothDevice d) async {
device = d;
// Connect to device
deviceConnection = _flutterBlue
.connect(device, timeout: const Duration(seconds: 4))
.listen(
null,
onDone: _disconnect,
);
// Update the connection state immediately
device.state.then((s) {
setState(() {
deviceState = s;
});
});
// Subscribe to connection changes
deviceStateSubscription = device.onStateChanged().listen((s) {
setState(() {
deviceState = s;
});
if (s == BluetoothDeviceState.connected) {
device.discoverServices().then((s) {
services = s;
for(BluetoothService service in services) {
for(BluetoothCharacteristic c in service.characteristics) {
if(c.uuid == new Guid("06d1e5e7-79ad-4a71-8faa-373789f7d93c")) {
_writeCharacteristic(c);
} else {
print("Nope");
}
}
}
setState(() {
services = s;
});
});
}
});
}
I have changed the original code so that it prints me the notifications as soon as I perform the writing method. The notifications should show me a standard message that is in the firmware of the device, but instead it is printing me the Local Name of the bluetooth chip, being that if I select the service and characteristic manually the return is the correct message.
You'd need to elaborate how you're executing writes on the descriptor - inside _writeCharacteristic(c).
BluetoothDescriptor.write() is a Future per docs, you should be able to catch any errors thrown during write.

Xamarin Forms does not wait for GeoLocation approval on iOS

I am have Xamarin Forms cross platform application for iOS, Android and UWP. I use the Xam.Plugin.Geolocator to get the location from each of the devices. My challenge with iOS is on the first launch of the app on a device. My code runs through and detects that IsGeolocationEnabled for the Plugin.Geolocator.Abstractions.IGeolocator object is false before the use is ever presented with the option to allow the application to use the device's location. This causes my app to inform the user that Location Services are not enabled for the application.
Basically I am hitting the line of code below before the use is ever asked about location services:
if (!App.gobj_RealGeoCoordinator.IsGeolocationEnabled)
ls_ErrorMessage = resourcestrings.GetValue("NoLocationServicesMessage");
On the other platforms, UWP at least, it seems that the app is paused while waiting for the user to respond to the request to use location services. Android just seems to automatically allow access to location if an app uses it.
Any idea how I can have the iOS detect if the request to use location services has been answered or not on the first run? Any suggestions would be greatly appreciated.
UPDATE(1):
I have all the correct items in my info.plist as seen below. I do eventually get the request to use the location just after my app has already checked IsGeolocationEnabled and decided the user has not enabled location services for the app.
UPDATE (2):
So I made a little progress using the following code.
try
{
while (!App.gobj_RealGeoCoordinator.IsGeolocationEnabled)
{
await Task.Delay(1000);
}
ViewModelObjects.AppSettings.CanAccessLocation = App.gobj_RealGeoCoordinator.IsGeolocationEnabled;
}
catch (Exception ex)
{
XXXXXXX
}
The challenge is that the plugin appears to provide me no way of knowing in the user has not responded to the location services dialog (i.e. IsGeolocationEnabled == false) versus the user said no to the location services dialog (also IsGeolocationEnabled == false). Any suggestions?
The way this type of permission request occurs on iOS is through an asynchronous dialog prompt, which is only shown if needed (and not until it is needed). Basically, you need to set up a callback from the CLLocation API. I have a helper class that I use for this purpose, which makes it even easier. Just call GetCurrentDeviceLocation() and pass it a callback function. The callback will only be invoked once the user has granted permission to the app, or if they previously granted permission:
public class GeoLocationService
{
readonly CLLocationManager _locationManager;
WeakReference<Action<Position>> _callback;
public GeoLocationService()
{
_locationManager = new CLLocationManager ();
_locationManager.AuthorizationChanged += AuthorizationChanged;
}
void AuthorizationChanged (object sender, CLAuthorizationChangedEventArgs e)
{
Action<Position> callback;
if (_callback == null || !_callback.TryGetTarget (out callback)) {
return;
}
if (IsAuthorized(e.Status)) {
var loc = _locationManager.Location;
var pos = new Position(loc.Coordinate.Latitude, loc.Coordinate.Longitude);
callback (pos);
}
}
static bool IsAuthorized(CLAuthorizationStatus status)
{
return
status == CLAuthorizationStatus.Authorized
|| status == CLAuthorizationStatus.AuthorizedAlways
|| status == CLAuthorizationStatus.AuthorizedWhenInUse;
}
public void GetCurrentDeviceLocation (Action<Position> callback)
{
_callback = new WeakReference<Action<Position>> (callback);
if (UIDevice.CurrentDevice.CheckSystemVersion (8, 0)) {
if (_locationManager.Location == null) {
_locationManager.RequestWhenInUseAuthorization ();
return;
}
}
AuthorizationChanged (null, new CLAuthorizationChangedEventArgs (CLAuthorizationStatus.Authorized));
}
}

Titanium/ Appcelerator/ Alloy: Unable to get current location despite success returning true

I am running the following code using the iPhone 4s simulater:
Ti.Geolocation.getCurrentPosition(function(e){
Ti.API.log(JSON.stringify(e));
});
A formatted version of the output of the above gives the following information:
{
"code": 0,
"type":"location",
"error":"The operation couldn’t be completed. (kCLErrorDomain error 0.)",
"source":{},
"success":true
}
There seems to be quite contradictory information. It says success is true yet gives an error message.
Furthermore, according to the Location Results Docs, it says that if success is true, it should return a coords field. Yet the above does not have coords on it.
Please also note both of the following returns true so its not a permission issue:
Ti.Geolocation.locationServicesEnabled;
Ti.Geolocation.hasLocationPermissions(Ti.Geolocation.AUTHORIZATION_ALWAYS);
There are 2 things to take notes of:
locationServicesEnabled property for device
hasLocationPermissions method
First of all, you will need to check for 1st property to make sure that the device location is on.
Then you will check for hasLocationPermissions because this can be true even the device location is not on, which I think is your case.
Sample code for this:
var authType = Ti.Geolocation. AUTHORIZATION_ALWAYS;
if (Ti.Geolocation.locationServicesEnabled) {
if (Ti.Geolocation.hasLocationPermissions(authType)) {
// voila...
} else {
Ti.Geolocation.requestLocationPermissions(authType, function (e) {
if (e.success) {
alert('voila...');
}
});
}
} else {
alert('Please turn on your device's location');
}

Arabic input fields in unity

Is there is a way to change the language of input fields in unity to Arabic?. I tried ArabicSupport and it displayed Arabic correctly but using it with input fields didn't work because
GameObject.Find("input_field")
.GetComponent<InputField>().text = Fix3dTextCS.fix(
GameObject.Find("input_field").GetComponent<InputField>().text
);
caused an error so, if I printed the input text elsewhere, it will appear correctly but how can I do it with the same input field?
input field is a little bit tricky to let it work with Arabic Support
please try this opensource asset it has an prefab for Arabic Input Field and some other UIs.
OpenSource for ArabicSupport Solution Link
OpenSource for unity asset UI Arabic Support: Link
Have you tried adding arabic font in that input.
If so, post the error message it may help to find the bug
Using Font won't help because it will only change the theme of your current Input usage but not how you use to input in the Device.
You will need to use Input.Location <- Input is static so you can access it anywhere. The only problem is, I am not sure what is the exact variable for arabic is. My best guess is Input.Location = "Arabic" or "arabic".
If you want to automatically detect their location, the GPS which will unity3d turn on by calling Input.Location.Start, and turn off by Input.Location.Stop()
Here is a sample code for you.
using UnityEngine;
using System.Collections;
public class TestLocationService : MonoBehaviour
{
IEnumerator Start()
{
// First, check if user has location service enabled
if (!Input.location.isEnabledByUser) yield break;
// Start service before querying location
Input.location.Start();
// Wait until service initializes
int maxWait = 20;
while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
{
yield return new WaitForSeconds(1);
maxWait--;
}
// Service didn't initialize in 20 seconds
if (maxWait < 1)
{
print("Timed out");
yield break;
}
// Connection has failed
if (Input.location.status == LocationServiceStatus.Failed)
{
print("Unable to determine device location");
yield break;
}
else
{
// Access granted and location value could be retrieved
print("Location: " + Input.location.lastData.latitude + " " + Input.location.lastData.longitude + " " + Input.location.lastData.altitude + " " + Input.location.lastData.horizontalAccuracy + " " + Input.location.lastData.timestamp);
}
// Stop service if there is no need to query location updates continuously
Input.location.Stop();
}
}

Resources