Altbeacon - Samsung Galaxy s9 not ranging beacons as expected when locked and power cable unplugged - altbeacon

I'm using the Altbeacon library and implementing the foreground service to allow for faster ranging. My app is designed to send a notification to the user whenever a matching beacon is ranged. The goal is that this happens no matter what, phone locked, unlocked, app open, app closed, and app cleared from task manager.
The app works as expected with a Samsung Galaxy s7 running Android 8.0. The issue I'm experiencing with the Samsung Galaxy s9 running Android 8.0, is when the power button is pressed to lock the phone. The phone no longer receives the notifications as often as it should, as if the foreground beacon scanning is being blocked.
The device sending the beacons can transmit a new beacon continuously at a 25ms rate for 12 seconds, for testing purposes, at the end of the 12 seconds it is set to repeat that process. The user should receive a new notification every 12 seconds, however the s9 may only receive 1 notification and then 5 could be missed before is sees another. The s7 will receive every single notification as expected.
The background scan rate is set to scan for 1.1 secs and wait for 10 seconds. I wish I could provide logs for the issue but when the phone is plugged in the issue doesn't occur, so I can't really pin point why the s9 would be acting this way when the s7 doesn't. I assume it has to be something with doze mode or sleep mode since when the power cord is plugged in, the s9 receives all the notifications as expected. Those are the only two phones I have been able to test so I don't know if it is also an issue with the s8.
What could be causing the s9 to not range the same as the s7 when locked by the power button? If the phone just goes to sleep on its own, it acts the same as if the power button were pressed to put it to sleep. Code snippet below.
Thanks!
mBeaconManager = BeaconManager.getInstanceForApplication(this.getApplicationContext());
set_forground_notification(true);
logManager.setLogger(Loggers.verboseLogger());
logManager.setVerboseLoggingEnabled(true);
mBeaconManager.setAndroidLScanningDisabled(false); // Setting to false allows low latency scanning
mBeaconManager.setRegionStatePersistenceEnabled(false);
mBeaconManager.setBackgroundScanPeriod(1100);
mBeaconManager.setForegroundScanPeriod(1100);
mBeaconManager.setForegroundBetweenScanPeriod(2000);
mBeaconManager.setBackgroundBetweenScanPeriod(10000);
mBeaconManager.setBackgroundMode(true); // this is being set to true here so that on app termination
// or reboot when the app starts back up because of the service, the scanning period
// is set to background and not foreground
private void set_forground_notification(boolean post)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (post) {
String CHANNEL_ID = "Scanning_for_device";
CharSequence name = "Scanning_for_device";
NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, android.app.NotificationManager.IMPORTANCE_HIGH);
mChannel.setShowBadge(false);
mChannel.setSound(null,null);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_foreground_logo)
.setContentTitle("Scanning for Device")
.setSound(null)
.setOnlyAlertOnce(true);
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(pendingIntent);
android.app.NotificationManager mNotificationManager =
(android.app.NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.createNotificationChannel(mChannel);
// sends foreground notification and starts foreground scanning?
mBeaconManager.enableForegroundServiceScanning(mBuilder.build(), 457);
} else {
// removes foreground notification and stops foreground scanning?
mBeaconManager.disableForegroundServiceScanning();
}
}
}

Related

How to using Firebase Notification. I can't turn on display device with received notification?

I followed the instructions to send notice of Firebase Notification following the instructions of Microsoft. But when the android device receives the notification does not light up the screen. I tried attaching WakeLock to turn on display but it didn't work?
All method are in the OnMessageReceived function.
var wakeLock = powerManager.NewWakeLock(WakeLockFlags.ScreenDim |
WakeLockFlags.AcquireCausesWakeup, "Demo");
wakeLock.Acquire(2 * 1000);
//////Send Notification here
wakeLock.Release();
Well you can use this method that uses power manager to turn on the screen light
private List<WakeLock> TurnDeviceLightOn(Context context)
{
PowerManager pm = (PowerManager)context.GetSystemService(Context.PowerService);
bool isScreenOn = pm.IsInteractive;
if (!isScreenOn)
{
WakeLock wl = pm.NewWakeLock(WakeLockFlags.Full | WakeLockFlags.AcquireCausesWakeup | WakeLockFlags.OnAfterRelease, "myLock");
wl.Acquire(10000);
WakeLock wl_cpu = pm.NewWakeLock(WakeLockFlags.Partial, "myCpuLock");
wl_cpu.Acquire(10000);
return new List<WakeLock>() { wl, wl_cpu };
}
return null;
}
This method returns the wake-locks which can be released at a later point of time
According to your description, your code can turn on screen when device is sleep, but for Firebase notification, you should know:
Notification messages are delivered to your onMessageReceived callback only when your app is in the foreground.
If your app is in the background or closed then a notification message is shown in the notification center, and any data from that message is passed to the intent that is launched as a result of the user tapping on the notification. So the onMessageReceived event is not fired. If you add your code in this event, I think it doesn't work.

Altbeacon and bootstrap always defaults to default beacon format

I have used the Alt-Beacon reference application as a starting point on how to implement bootstrap regions. The application restarts if killed but the beacon format is always being set to Alt-Beacon and not iBeacon.
Logcat on startup:
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
Bootstrap code:
beaconManager = org.altbeacon.beacon.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.setBackgroundBetweenScanPeriod(5000l);
beaconManager.setBackgroundScanPeriod(1000l);
beaconManager.setRegionStatePersistenceEnabled(false);
Region region = new Region("backgroundRegion",null, null, null);
regionBootstrap = new RegionBootstrap(this, region);
BackgroundPowerSaver backgroundPowerSaver = new BackgroundPowerSaver(this);
I would expect that when the app was restarted I should see:
m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24
I am using 2.15.2 of AltBeacon in Android Studio 3.1.3 with test device of Samsung S5 Mini running Android 6.0.1
Further information: When the phone is rebooted and the USB connected I would expect to see the app start and listen for iBeacon packets. It appears to restart but is killed by the OS.
Logcat:
12-07 17:32:08.132 8359-8359/net.simplesdktest I/InstantRun: starting instant run server: is main process
12-07 17:32:08.212 8359-8359/net.simplesdktest I/BeaconManager: BeaconManager started up on pid 8359 named 'net.simplesdktest' for application package 'net.simplesdktest'. isMainProcess=true
12-07 17:32:08.357 4889-4889/? I/TaskManager:PackageInfo:
getRunningAppProcesses() - proc:net.simplesdktest, pkg:net.simplesdktest, uid:10346, pid:8359
12-07 17:32:12.822 2390-3458/? I/ActivityManager: Killing 8359:net.simplesdktest/u0a346 (adj 15): DHA:empty #21
setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24"));
This one detects ibeacon format BLE beacons doesn't it?
Source
It appears that when the beacon manager is first created it adds the AltBeacon format by default. I have managed to clear this out and set iBeacon which is now being detected.

Parsing Beacon Information in didEnterRegion Method of Altbeacon Library

I would like to use the didEnterRegion method in association with the RegionBootstrap or MonitorNotifier in my application. Currently I'm using the RegionBootstrap but perhaps the MonitorNotifier is better for my application.
In particular I'm adding an iBeacon parser to the beaconmanager and then setting "Id1" of a region to look for the UUID portion of my iBeacon and setting "Id2" and "Id3" to Null. Though they are set to Null in the Region, I would like to be able to parse the information from those locations upon entering the didEnterRegion method. I'm using "Id2" (Major) and "Id3" (Minor) to provide random identification parameters of the beacons.
This information along with a portion of the data from the UUID would then be sent in a notification to the phone user. When testing, I'm entering the didEnterRegion method but the data that is provided is only that which matches the set region of "Id1". If someone could provide any insight at all, it would be greatly appreciated!
I would also like to receive the didEnterRegion method for the same iBeacon every 10 seconds, but with testing it appeared that once that particular iBeacon was seen once, didEnterRegion wouldn't get a subsequent call again. Any way to clear that the iBeacon was captured so that subsequent captures could happen?
I'm trying to keep the battery usage as low as possible and when using the scanRecord data from a onNonBeaconLEScan to parse the information, I'm noticing significant battery drain even when setting the foreground and background time "BetweenScanPeriod" to something really large. I really only need to see that the iBeacon entered the region and pull the information, then 10 seconds later do it again.
Intended application flow -
User enters region of beacon with matching UUID (ID1)
Beacon information from ID2 and ID3 are parsed and sent along with ID1 to user via notification
10 seconds later user receives another notification with same data
repeat until person leaves region or iBeacon stops transmitting
The simplest way to get the information you need is to enable ranging in the didDetermineStateForRegion callback:
public void didDetermineStateForRegion(int state, Region region) {
beaconManager.startRangingBeaconsInRegion(region);
beaconManager.addRangeNotifier(this);
}
public void didRangeBeaconsInRegion(Region region, List<Beacon> beacons) {
for (Beacon beacon : beacons) {
Identifier id2 = beacon.getId2();
Identifier id3 = beacon.getId3();
// Now do something with id2 and id3
}
}
The didRangeBeaconsInRegion callback will be made every 1100 ms with default settings, but you can change this to be 10 seconds if you wish with a line like this the first time you access the BeaconManager:
beaconManager.setScanPeriod(10000l);
beaconManager.setBetweenScanPeriod(0l);
In terms of battery, if you want to be getting scan updates every 10 seconds, you will be using a lot of battery, because this means doing almost constant bluetooth scans. In the background, you may wish to back off and do a 10 second scan only once every 5 minutes with this:
beaconManager.setBackgroundScanPeriod(10000l);
beaconManager.setBackgroundBetweenScanPeriod(290000l);
BackgroundPowerSaver powerSaver = new BackgroundPowerSaver();

Settings alarms while app is closed

How can I set local notifications with out forcing user to open app.
I need my app set a local notification for sunrise and sunset, but I don't want to ask people open app.
I know I can have up to 64 notifications via scheduleLocalNotification, but I need to set it for a year so I should be able to run app in background and set alarms for future sunrises and sunsets in background.
The simple answer is you can't. Your app can't run whenever it wants in the background; it can't schedule a timer to wake itself up to post more notifications when they are due.
The only way you could come close to something like this is by having a server which send a background push notification to your app as a wake-up call when a new batch of 64 notifications are coming close to needed to be posted.
However this would be relying on the fact the user doesn't terminate your app. If the user does then you'd have to send a non-background push notification to the user and hope they click on it to launch your app.
Android Awareness API has recently announced new features that provide a simple solution for your use-case (that avoids you having to explicitly manage location request or computing sunrise times). The way to achieve what you're trying to do is to create and register a TimeFence specified relative to sunrise/sunset.
For example:
// Create TimeFence
AwarenessFence sunriseFence =
TimeFence.aroundTimeInstant(TimeFence.TIME_INSTANT_SUNRISE,
0, 5 * ONE_MINUTE_MILLIS);
// Register fence with Awareness.
Awareness.FenceApi.updateFences(
mGoogleApiClient,
new FenceUpdateRequest.Builder()
.addFence("fenceKey", sunriseFence, myPendingIntent)
.build())
.setResultCallback(new ResultCallback<Status>() {
#Override
public void onResult(#NonNull Status status) {
if (status.isSuccess()) {
Log.i(TAG, "Fence was successfully registered.");
} else {
Log.e(TAG, "Fence could not be registered: " + status);
}
}
});
You will get callbacks when the fence evaluates to TRUE at sunrise, and when it evaluates back to FALSE at 5-min after sunrise.
Please check Fence API code snippets docs for how to add your custom app logic.

does anyone know _UIApplicationDidRemoveDeactivationReasonNotification?

when ever a _UIApplicationDidRemoveDeactivationReasonNotification notification is posted
(which is an apple private NSNotification) it holds a NSNumber in it's userInfo,
does anyone know, what does each number mean?
the key is _UIApplicationDeactivationReasonUserInfoKey
all I know so far number 5 means app resigned active for InAppPurchase-verification
(which is an OS message and makes your app inactive until user clicks 'Cancel' or 'Buy')
So I needed this and I got a few values decoded.
I am looking at another similar notification _UIApplicationWillAddDeactivationReasonNotification
with same value key _UIApplicationDeactivationReasonUserInfoKey
here they are (for ios6/7):
// notification/control center overlay
kDeactivationReasonControlOverlay = 1,
// double tapped for the task manager mode
kDeactivationReasonTaskManager = 2,
// app is going inactive, eg: locked, enter background, power off screen, phone call, voice control (not siri)
kDeactivationReasonLockScreen = 3,
// system alerts, eg: privacy permissions, IAP dialogs
kDeactivationReasonSystemAlert = 5,
// siri overlay
kDeactivationReasonSiriOverlay = 6,
However I don't have a test case which i can reproduce 4.
And I don't know if 0 or values above 6 are valid values, if anyone knows please comment!

Resources