I have developed a device Admin app that applies policies to the device eg restrictions etc.
How my system works
The webapp sends a push notification to the device via FCM. I used to use GCM and a wakelock.(The latter worked fine). When the push notification comes through to the device, the firebase class that receives the push calls an IntentService. This IntentService then processes the message eg "MOBILEDATA_ON" and any data associated with the message. Once the message has been processed eg MOBILEDATA_ON, the service executes code that turns the mobile data on and then calls a webservice relaying the state back to the webapp.
I chose IntentService as it is Async and is capable of making http calls to relay the state back with no extra async code.
All this works fine when the device is awake, even if the app is in the background.
The problem
If the device is unplugged and untouched for a while, it goes into Doze/Standby mode. (it is an Android 6 device). This is normal behaviour, however if i send a push to the device, the device does receive it and executes the correct code to apply the functionality but unfortunately the webcall that relays the new state of the device is not executed.
so for example, if Bluetooth is switched off on my device and it is in doze mode, i can send a push which switched bluetooth on successfully but the webapp never receives the updated state.
I have set the priority to high in FCM when sending the push, and this why i do receive the push when the device is in Doze.
My app is a Device Admin app, the docs says
The app is an active device admin app (for example, a device policy
controller). Although they generally run in the background, device
admin apps never enter App Standby because they must remain available
to receive policy from a server at any time.
Optimizing for doze
Can anyone tell me why the webcalls are not executing sending the state back to server when in Doze/Standby mode?
[EDIT1]
I used the following code to create a wakelock. At first i acquired the lock in the IntentService, executed the functionality then released it all in the same service. This was good for most cases but some of my functionality includes finding device location via another IntentService called Tracking service.
The problem is that GPS could take say 20 seconds to find a lock by which time the original Intentservice has finished and the device went back to sleep.
To get around this i created 2 methods in the application Object to acquire and release the lock. this way, if the push is one for location i can do a check in the initial service(which normally releases it) to see if the push is a location one and not release it there. Instead the tracking service can make a call to the Application Object to release when GPS is found.
A partial wakelock didn't seem to work as intended so i found the following code that uses a full wakelock. This is depreated though. Is the an alternative to using FULL_WAKE_LOCK?
public void acquireWakeLock(){
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
"MyWakelockTag");
wakeLock.acquire();
Log.e(TAG, "just acquired wakelock");
}
public void releaseWakeLock(){
wakeLock.release();
Log.e(TAG, "just released wakelock");
}
thanks
Matt
Related
I have created the application for getting the Users latlong and send them to the server. So, now we have created the Foreground services for the getting the USER's location and is working fine in the All the other devices including the Android OS 9.0.
But in the specific OnePlus 5T Android 9.0 device the foreground service stops working when the device is locked and Service is also terminated after one hour, also even after we have disabled the deep cleaning option there.
Please let us know if there is something with the Device specific config that we need to change for working foreground service continuously.
Reason behind that- Alarm manager is not calling on time even if you are using setAndAllowWhileIdle() or setExactAndAllowWhileIdle() it won't work and pending intent also get destroy, Only High priorities task get executed in system like FCM push notification.
So the solution I found is :- implement push notification in your android application and send data message through push notification and start service from
public void onMessageReceived(RemoteMessage remoteMessage) {
//start your service from this method
}
note :- Check your Force Stop button of that application is enable or disable
if its disabled that means system complete killed your application
Android doze-standby mode and idle mode
Context
We are developing an android app that is supposed to do the following:
the user installs the app, registers and closes the app
once or twice a year an admin sends a Firebase data message with priority high to the user containing a geo fence
the FCM message starts a JobService that locates where the phone is
if the phone is inside the given area an Activity is started and user interaction starts
if the phone is outside the area the service is stopped and the user is never disturbed
I developed the app based on the Firebase push example found here
The problem
The application works fine on my older phones but on my new test phone (android 8.1.0, LineageOS 15.1) we have a problem when the phone is in sleep mode. In this case the FCM message arrives instantly but the service is first started once the phone is unlocked. So the message is stuck between 2. and 3.
We need the app to respond at once - not when the user decides to use his phone 2 hours later.
I assume the problem is due to the Doze mode introduced with android 6. I tried to solve it by adding the app to the whitelist in settings->battery->battery optimization but this did not solve the problem.
Questions
Is it Doze mode that delays my app between 2. and 3.? If so why is it not solved when the app is in the whitelist?
Is there any other way to start the location service at once? This post suggests that a foreground service can do it but this requires that a notification is shown which breaks with 5.
Is there another way to start my service at once besides whitelist and foreground service?
Yes! you are right this may be due to the Doze and App Standby features introduced in API 23 Marshmallow.
As mentioned in the documentation, the system do ignore wakelocks and system doesn't allow JobScheduler to run, which effectively prevents your app from running the Job.
An easy and effective workaround would be to run Location detecting routine inside a normal background service and start it using startService() when you receive FCM push.
Note that you might still need to white-list your app because as mentioned in another post here, only a whitelisted app can use the network and hold partial wake locks.
Is it Doze mode that delays my app between 2. and 3.?
From the documentation Doze mode affect Network access and blocks JobScheduler.
If so why is it not solved when the app is in the whitelist?
Also from the documentation: An app that is whitelisted can use the network and hold partial wake locks during Doze and App Standby. However, other restrictions still apply to the whitelisted app, just as they do to other apps.
So the blocking of JobScheduler still applies.
Is there any other way to start the location service at once? This
post suggests that a foreground service can do it but this requires
that a notification is shown which breaks with 5.
Ignore Battery Optimizations (for Internet access) in combination with an AlarmManager with setAndAllowWhileIdle() or setExactAndAllowWhileIdle() should work.
Be careful with Ignore Battery Optimizations
Google Play policies prohibit apps from requesting direct exemption from Power Management features in Android 6.0+ (Doze and App Standby) unless the core function of the app is adversely affected.
I think an important question here is: Do you really need to execute the JobScheduler immediately.
If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode.
If the device is in Doze mode, it means the user is not using it.
if the phone is inside the given area an Activity is started and user interaction starts
This is the step Doze blocks
We need the app to respond at once - not when the user decides to use his phone 2 hours later.
If the device is in Doze it means the user is not interacting with it. Even if you show the Activity the user is not using the phone, he will see it when he starts using it 2 hours later :)
I still didn't try that,
but you might use a WakefulBroadcastReceiver:
https://developer.android.com/training/scheduling/wakelock.html
https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html
According with this links, you should declare your receiver as:
public class YourReceiver extends WakefulBroadcastReceiver {
Probably your receiver is already a WakefulBroadcastReceiver because notifications are showing..
In the receiver, you start the service (your service has to be an IntentService) using:
startWakefulService(context, your service);
Finally, remember to release the wake lock in the service:
#Override
protected void onHandleIntent(Intent intent) {
<Your_broadcast_receiver_class>.completeWakefulIntent(intent);
}
I hope it helped
Can Pusher messages be received on Android/iOS app when the app is closed or the phone is turned off?
What i expect to happen...
When phone is on & app is on, it's pretty straight forward from the Pusher docs on how to react to pusher messages sent to the app.
When phone is on & app is closed, the phone should receive a notification that something has been sent to the app.
When phone is turned off, a notification should be received by the phone when it's turned back on to notify that something has been sent to the app.
Are these even possible? If yes, what are some suggestions to lookout for? If no, what can be some workaround?
When an application using Pusher moves into the background on iOS and Android the connection to Pusher will likely stay active for a few minutes. But eventually that connection will be closed. You can't stop that happening within your application (although there may be a "hack" around stating your app is a Voice app when submitting to the Apps store).
Therefore, you should monitor your application moving to the background and put a fallback in place to delivery messages to the phone when it's not connected.
Please see How get pusher events when the iOS app go to the background? for libPusher (the Pusher iOS library).
Here's an extract from the Android Processes & Threads Lifecycle docs on a "Service Process":
A process that is running a service that has been started with the startService() method and does not fall into either of the two higher categories. Although service processes are not directly tied to anything the user sees, they are generally doing things that the user cares about (such as playing music in the background or downloading data on the network), so the system keeps them running unless there's not enough memory to retain them along with all foreground and visible processes.
So, running a Pusher instance in such a thread is a viable option.
However, there will still be occasions where the user goes offline. In that situation your server you can detect if a user is online by querying the Pusher HTTP API or by using WebHooks where your server can be instantly informed if the user has gone offline or come back online.
Using the mechanisms above you can facilitate smart notifications; if the user is online (the app is in the foreground) then send the message to them by Pusher, if they are offline (the app is in the background) then use an alternative mechanism for delivery (native Push Notification, SMS or email).
I'm building an App which does some communications with a server using GCM. It works all fine but one.
I've implemented an instant chat which sends notifications to the other android device that there is a new message.
If the other device clicks on the noti, it will enter the instant chat room to reply, or just see newly updated messages.
I'm doing this by comparing a flag from the server ; if the message is the first one to send and the app or device is sleeping, it will make a noti which can link to the new chat room.
If the message is from the currently running chat room, it will just update it.
But as you can easily see, it can't do anything if the device receiving the message is not awake.
So I want to tell if the device state is awake of not to decide whether the message is from a new chat room, or from a current one.
If it's from a new one(when the device is sleeping), it will display a noti which will lead to the newly made chat room, and if it's from the current chat room, it will just update the chat log.
I think you need to study PowerManager API for android.
PowerManager Link
From what i can tell you can use the method isInteractive() or isScreenOn() depending on what version of android your on(isScreenOn was deprecated in API level 20 and is replaced by isInteractive) to check if the screen is off.
But i will advise against using isScreenOn() there is no guarantee that the device will go to sleep after the screen is turned off. This is upto the OEM.
Best you can do is keep the device awake using Wakelock
Wakelock Link
I solved this issue by following this link.
How can I tell if Android app is running in the foreground?
by the answer of Gadenkan, I made an activityManager object to check if my app is running in the foreground.
So, if it is not running on the foreground, it will call the entire app to start from the main activity to the chat room.
If not, it will just tell the broadcastlistener to append new messages by the GCM.
When an Android device receives mail, does it do this by periodically connecting to the mail server? When the device is in standby mode where the screen is off, I assume that the standard mail app also is shut down but possibly uses the AlarmManager to awake and then check the mail. I can't imagine that the mail app is always running with a full Wakelock turned on, keeping the CPU always running, as that would drain the battery.
The reason I need to know this is because my own app needs to get a notification from its own server when certain events take place. I could just as well implement a repeating alarm that activates my app periodically and checks for the notifications. But if the mail client already is waking up at a regular time interval, I probably can save on battery consumption by using e-mail to notify my app instead. For this to work though, it must be possible for the mail app to launch my app when it receives e-mail. I doubt that this is possible, or is it?
This is what you wnat to use:
Google Cloud Messaging