Wearable.DataApi.putDataItem not being called from Jobservice in Oreo - wear-os

Due to Background Service Limitations in Oreo, I put up my Service (used in Nougat, API 25) to send data to Wear (API 23) using Jobscheduler (as recommended replacement).
There I am using an AsyncTask to send data to my wearable.
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/nextAppt");
putDataMapReq.getDataMap().putLong("appt", nextAppt);
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
putDataReq.setUrgent();
PendingResult<DataApi.DataItemResult> pendingResult =
Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
This works fine as a regular Service (pre-Oreo), but not from a Jobservice (no matter if my MainActivity is in foreground or not). There is also no error message, etc. Just that nothing arrives at my Wear-device.
As I want to avoid using a foreground Service I am out of ideas right now, how to accomplish this or why exactly it does not work...

Related

Android Beacon Library - didEnterRegion not firing when app in background or stopped for pre-Android 8

First some background:
My setup uses a Service, which implements BeaconConsumer and binds to the BeaconManager. I have additional handling so when my app leaves the foreground, I move my Service to run in foreground, and when my app enters the foreground, I move my Service to run in background. That way, the persistent notification should display if and only if the app isn't displaying. In accordance, I am using the pattern here to tell BeaconManager I'm running this Service in the foreground, to allow for more frequent scanning. The link above isn't quite clear about this, but I believe this pattern should work without alterations needed on both pre-Android 8 as well as Android 8+. It shouldn't be strictly necessary on pre-Android 8, since the OS is more lenient. However, using this setup across all versions has the collateral benefit of ensuring that the OS does not kill the Service. If the app is in the foreground, the Service is background but has priority by virtue of the app, and if the app is not in the foreground, the Service is, and therefore has priority.
Now the problem: On pre-Android 8 devices, my Service is not seeing didEnterRegion called when the app is not in the foreground (but the Service is). It works fine on Android 8+.
some code snippets:
In my Service, set up the BeaconManager, set scan intervals
_beaconManager = BeaconManager.getInstanceForApplication(this);
_beaconManager.getBeaconParsers().add(new BeaconParser().
setBeaconLayout(IBEACON_PATTERN_1));
_beaconManager.setEnableScheduledScanJobs(false);
_beaconManager.setBackgroundBetweenScanPeriod(0);
_beaconManager.setBackgroundScanPeriod(1100);
Function in my Service I invoke to send the service to the foreground, and background:
private void sendServiceToForeground() {
this.startForeground(NOTIFICATION_ID, _notification);
if (_beaconManager != null) {
if (_beaconManager.isBound(this)) {
_beaconManager.unbind(this);
}
_beaconManager.enableForegroundServiceScanning(_notification, NOTIFICATION_ID);
_beaconManager.bind(this);
}
}
private void sendServiceToBackground() {
if (_beaconManager != null) {
if (_beaconManager.isBound(this)) {
_beaconManager.unbind(this);
}
_beaconManager.disableForegroundServiceScanning();
_beaconManager.bind(this);
}
this.stopForeground(true);
}
I can provide more code as requested. Not sure what all is relevant.
Calls to unbind() and bind() are asynchronous, so calling them one after another will be a problem unless you first wait for the unbind() operation to complete. This is tricky, because the library's BeaconManager does not provide a callback to tell you when unbind is complete (indeed, this is because the underlying Android service APIs also do not provide such a callback. You essentially don't know when the library's scanning service has stopped so you can safely restart it again in a different mode.)
It's a bit of a hack, but you might try adding a delay between unbind() and bind() to see if that makes a difference.

How to receive PROVIDERS_CHANGED broadcast in Android Oreo

Apps handle GeoFence needs to receive PROVIDERS_CHANGED broadcast since:
Registered GeoFences will be removed when both 2 location providers
(network and GPS) are turned off.
When one of 2 location providers is turned on, app needs to register
GeoFences to work. This should be performed w/o asking user to run
my app again.
So my app has been registering its broadcast receiver in manifest. But it does not work any more in Android Oreo since PROVIDERS_CHANGED is not one we can make it work as before.
I can register broadcast receiver for that in app's activity or in service but it will quit (end its life cycle) sooner or later, then I need to unregister it. My app starts working by some events like GeoFence transition, but receiving PROVIDERS_CHANGED is critical to make it work.
I verified PROVIDERS_CHANGED can't be received by receiver registered in manifest in Android Oreo. Is there any solution for it?
#Tomcat and #Virat18 - I've come across a solution to the fact that you can no longer register a Broadcast Receiver in your Manifest to receive the PROVIDERS_CHANGED action Intent-filter in Android-OREO..
The solution? Simply register your BroadcastReceiver dynamically (from within your code), instead of from the Manifest.. Also, instead of checking for the hard-coded regex android.location.PROVIDERS_CHANGED, you should use LocationManager.PROVIDERS_CHANGED_ACTION (and of course import the LocationManager).
Here is an example of the Code I used to get this to work! (ex: from a Button Click):
public void buttonClick(View view) {
IntentFilter filter = new IntentFilter();
filter.addAction("android.location.PROVIDERS_CHANGED");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().matches(LocationManager.PROVIDERS_CHANGED_ACTION)) {
Log.i(TAG, "Action MATCHES LocationManager.PROVIDERS_CHANGED_ACTION!");
}
}
};
this.getApplicationContext().registerReceiver(receiver, filter);
Log.i(TAG, "RECEIVER HAS BEEN REGISTERED");
}
Also, don't forget to unregister the receiver in your code appropriately.
If you find this to be a good solution, please accept it as the Answer.
Happy Coding!
PS. This will continue to receive the broadcast from the background, even once the User leaves your Activity (presses the back-button, home-button, etc).. However, if the user closes your App from the Multitask button, it will no longer receive, so take note of that.

Android Wear Wake Mobile

Edit
I erased everything for clarity. as i am going to simplify my request for information:
What is best way to handle receiving messages from a wear on a mobile when the mobile is asleep or if app is not in the foreground?
During both these circumstances even though i send messages to the mobile from the wear, the mobile does not receive or process them. i do not know which.
if have read the following:
1) partial wakelocks - no good i dont want to really keep CPU awake
2) handler
3) broadcastreceiver
4) service
i do not know exactly what i should do in order to process messages with my app when app is not in the foreground and/or asleep.
If the onMessageReceieved() SHOULD process during sleep and or when app is not in foreground letting me know that would also be beneficial as right now i think it should not based on what i am seeing in my app.
Also i am using livelisteners instead of a listener service. is this my problem? if i instead switch to a wearablelistenerservice class will that solve my issues and work correctly?
i do this
#Override
public void onConnected(Bundle connectionHint) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Connected to Google Api Service");
}
Wearable.MessageApi.addListener(mGoogleApiClient, this);
}
instead of if i do this:
public class DataLayerListenerService extends WearableListenerService{
and put all my codes in there and then do this:
<service android:name=".DataLayerListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<data android:scheme="wear" android:host="*"
android:path="/start-activity" />
</intent-filter>
</service>
will that solve my not receiving messages problem when not in foreground and when phone is asleep? as this intent will act as a service that runs in the background?
You might want to check Keeping the Device Awake wherein it discussed different approaches that you can use such as keeping the CPU on.
As mentioned,
If you need to keep the CPU running in order to complete some work before the device goes to sleep, you can use a PowerManager system service feature called wake locks. Wake locks allow your application to control the power state of the host device.
You may find more tips and information in the use of wake locks from the given documentation.
Using a class that extends WearableListenerService and adding service to manifest worked for working while phone is off. Now i just need to implement and interact into the main feed to update data on the main screen

SignalR Hub method is not called

I have a SignalR hub and two clients (Windows and PCL for Android and iOS). Neither of the clients is able to call some methods on the server. This behaviour is quite odd, since the methods look very similar. Moreover, a colleague of mine is able to call methods I cannot call, and vice versa, does not invoke methods that I invoke with no problems.
Here is an example of a method, which works for me and does not work for my colleague:
public override async Task<bool> RefreshArray(User user, int waitMilis)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(waitMilis);
await Proxy.Invoke("RefreshArray", user);
return true;
}
catch (Exception ex)
{
OnExceptionOccured(ex);
return false;
}
}
And a method which does not work for me, but works for my colleague:
public override async Task<bool> RequestInformation(User user, Product product, int waitMilis)
{
var cts = new CancellationTokenSource();
try
{
cts.CancelAfter(waitMilis);
await Proxy.Invoke("RequestInformation", user, product);
return true;
}
catch (Exception ex)
{
OnExceptionOccured(ex);
return false;
}
}
Yes, me and my colleague have exactly the same code. And no, there are no typos or different arguments. I have tried to get as much data from the client connection as possible, by setting _connection.TraceLevel = TraceLevels.All; However, I did not get any information on the invoked methods, just on the replies from the hub. When calling RefreshArray, I got exactly the data I requested. When calling RequestInformation, the debugger never even hit the breakpoint in the hub method and the _connection.Trace displayed only this: 11:22:45.6169660 - 7bc57897-489b-49a2-8459-3fcdb8fcf974 - SSE: OnMessage(Data: {})
Has anybody solved a similar issue? Is there a solution?
UPDATE 1
I just realized that I have encountered almost the same issue about a year ago (Possible SignalR bug in Xamarin Android). StackOverflow has also pointed me to a question with almost the same issue (SignalR on Xamarin.iOS - randomly not able to call Hub method), just related to iOS and Azure. However, I got the same proble even outside Xamarin, on Windows Phone 8.1 and and Windows 10 Universal App. Moreover, I am running the server just locally, so it is not an issue od Azure. Is it really possible, that a 2 years old bug has no solution?
UPDATE 2
I have just created a simple console application with SignalR.Client. In the console application every method worked just fine. Amazingly, also the Windows 10 Universal Application started to behave as expected - every hub method was invoked correctly. Windows Phone 8.1 also improved its behaviour (all hub methods invoked). However, every now and then the connection tried to reconnect periodically (for no apparent reason), leading to Connection started reconnecting before invocation result was received. error. The Android application still behaved as before.
So I tried to replicate my previous steps and created another console application, but this time with SignalR.Client.Portable library. To my dissapointment, there was no change in the Android application behaviour.
Next week we will start to test our application on iOS, so I really wonder what new oddities will we encounter.
I have managed to solve the problem (at least so it seems). As it turned out, there is some weird stuff going around, when an application receives an answer from SignalR hub. It seems as if the HubProxy was blocked for a certain period of time on Android, while it drops the connection and starts to reconnect periodically on Windows Phone, not waiting for an asnwer from the hub.
The implementation of RefreshArray on the hub was something like this:
public async Task RefreshArray(User user)
{
await Clients.Caller.SendArray(_globalArray);
await Clients.Caller.SendMoreInformation(_additionalInfo);
}
Because the method sent two methods as an answer, the client Proxy got stuck and each platform handled it in its own unexpected way. The reason why some methods were called on my computer and not on colleagues was, simply, because we had different position of breakpoints, which enabled the application to resolve at least some requests and responses.
The ultimate solution was to add some synchronization into the invokation of methods. Now my hub calls only await Clients.Caller.SendArray(_globalArray);. This is then handled on the client with a ArraySent(string[] array) event, which then subsequently invokes the SendMoreInformation() method on the hub.

How can I test the background scan and launch the application in background with iBeacon-Android?

I am using the pro library.
But I just found doc for free library
I cannot find any doc for pro version.
Also, I don't know how to implement the background mode even using the pro sample.
Here are the steps:
Build the pro sample project
start the iBeacon source(using iPad) and it can be detected
start the application and then press home button the make it in
background
Turn off the iBeacon source
Turn on the iBeacon source
However, more than 5 minutes, the application does not launch
So, can anyone verify the step I did?
How can I test the background mode more easily?
Also, for the BootstrapNotifier, is it just work only first time when the device reboot?
After that, even I put application in background, the application will not launch when it detect iBeacon?
Your testing method sounds fine. I think the issue is that the reference app for the pro library only auto launches the app on the first detection after boot. After that, it sends a notification instead, and tapping on that notification launches the app.
This is purely for demonstration purposes. You can change it to auto launch on every detection if you wish. Simply alter the haveDetectedIBeaconsSinceBoot logic in this code:
#Override
public void didEnterRegion(Region arg0) {
// In this example, this class sends a notification to the user whenever an iBeacon
// matching a Region (defined above) are first seen.
Log.d(TAG, "did enter region.");
if (!haveDetectedIBeaconsSinceBoot) {
Log.d(TAG, "auto launching MainActivity");
// The very first time since boot that we detect an iBeacon, we launch the
// MainActivity
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// Important: make sure to add android:launchMode="singleInstance" in the manifest
// to keep multiple copies of this activity from getting created if the user has
// already manually launched the app.
this.startActivity(intent);
haveDetectedIBeaconsSinceBoot = true;
} else {
// If we have already seen iBeacons and launched the MainActivity before, we simply
// send a notification to the user on subsequent detections.
Log.d(TAG, "Sending notification.");
sendNotification();
}
}
The javadoc link was missing from the main documentation page when you posted this question. That is fixed now.

Resources