How to unlock device when service call - android

In my application, user starts the service it is open and it is called every 5 minutes. it works fine.
But I want to unlock automatically (call WAKE_LOCK ) whenever the service is called i.e. every 5 minutes.
How can I achieve this?
Any body please help me...
Edit 1#
private void handleIntent(Intent intent) { // obtain the wake lock
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, NAME);
mWakeLock.acquire();
}

You have to use the AlarmManager for that.
Set up of the alarm and its receiver : Notification activity called by AlarmManager NOT to pop up when app is closed
Then you have to convert your service to a wakeful intent service and then call WakefulIntentService.sendWakefulWork(context, YourService.class); inside onReceive(context)
At least this was the way to go - the latest android platform seems to support this (kind of) out the box : https://developer.android.com/reference/android/support/v4/content/WakefulBroadcastReceiver.html

Related

Run application in background when phone in Doze

Application is running SDK 23 and above. I am running some tasks using Service after completing the task and scheduling the next task using AlaramManager (setExactAndAllowWhileIdle). This is working fine. If the phone is idle continuously for 2 or 3 days then its going to Doze mode. After Doze mode ,application loosing the network and wakelock also not working.
Is there way even if phone is Doze can we run the application with any network interposition issues.I tried to keep the application witelist but i needs device to be rooted.
adb shell dumpsys deviceidle whitelist +<Package Name>
Can anyone suggest me which best way to run application without interruption?
Actually there is no way of doing this without running a foreground service. Having listed in white list may not be appropriate for your application and even though it is, you ask user to give you permission which can be seen as something dangerous from the end user's point of view.
However, I have a trick about this. Listen android's broadcasts and when you catch that device will move into doze mode, start a foreground service. In most of the cases user won't be able to see your foreground notification image and won't know that you are running a service. Because device is in the doze mode meaning it is stable in somewhere user not watching. So you can do whatever is needed.
You also listen broadcasts sent when doze mode is finished. When that happens, stop your foreground service and work in a normal logic of yours with alarm managers.
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(intent.getAction().equals("android.os.action.DEVICE_IDLE_MODE_CHANGED")){
if (pm.isDeviceIdleMode()) {
startForegroundService();
//stopAlarmManagerLogic();
} else {
stopForegroundService();
//startAlarmManagerLogic();
return;
}
return;
}
}
Edit-WakefulBroadcastReceiver is now deprecated
Firstly, instead of directly calling a service in the AlarmManager call a broadcast receiver which then calls the service.
The broadcast receiver should extend a WakefulBroadcastReceiver instead of a regular BroadcastReceiver.
And then, let the broadcast receiver schedule a new Alarm, start the service using startWakefulService() instead of startService()
public class MyAwesomeReceiver extends WakefulBroadcastReceiver {
int interval=2*60*60*1000;
#Override
public void onReceive(Context context, Intent intent) {
Intent serviceIntent = new Intent(context, MyAwesomeService.class);
Intent receiverIntent = new Intent(context, MyAwesomeReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 11, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+interval,alarmIntent);
startWakefulService(context, serviceIntent);
}
}
The WakefulBroadcastReceiver and startWakefulService() will let your app a 10 seconds window to let do what it needs to do.
Also,
You can always ask the user to let your app ignore battery optimization functionality using-
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
Intent intent=new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (powerManager.isIgnoringBatteryOptimizations(getPackageName())) {
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
}
else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + getPackageName()));
startActivity(intent);
}
and in the manifest
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"></uses-permission>
You can request android to whitelist your app for doze mode by sending a high pirority GCM message. But remember this might make your app not approved by Google Play:
Intent intent = new Intent();
String packageName = context.getPackageName();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName))
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
else {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
}
context.startActivity(intent);
https://developer.android.com/training/monitoring-device-state/doze-standby.html#whitelisting-cases
After Android N, no app can run in background forever. However you can use Firebase Job Dispatcher which can help you to run your app even if it is in doze mode. With the help of Firebase Job Dispatcher you can tell the system that your app should run at a particular time if provided conditions are matched.

request location updates not working during device sleep

I am using location manger class to receive location updates my requirement is such that I have to listen for contious location updates but the problem I am facing that once it disconnects I don't know how to reatablish GPS connection,furthermore in some device once device sleeps i m not able to receive any location updates please provide any solutions to achieve this any help is appreciated..
public void setup(MainActivity activity) {
if (!setup) {
this.activity = activity;
Intent locationIntent = new Intent(this.activity, LocationIntentService.class);
mLocationPendingIntent = PendingIntent.getService(this.activity, 0, locationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent detectedIntent = new Intent(this.activity, ActivityDetectionIntentService.class);
mDetectedActivityPendingIntent = PendingIntent.getService(this.activity, 0, detectedIntent, PendingIntent.FLAG_UPDATE_CURRENT);
googleApiClient = new GoogleApiClient.Builder(activity)
.addConnectionCallbacks(activity)
.addOnConnectionFailedListener(activity)
.addApi(ActivityRecognition.API)
.build();
setup = true;
}
}
**LocationIntentService.java**
public class LocationIntentService extends IntentService {
public LocationIntentService() {
super("LocationServices");
}
public LocationIntentService(String name) {
super("LocationServices");
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent != null) {
Location location = intent.getParcelableExtra(LocationManager.KEY_LOCATION_CHANGED);
if (location != null) {
Intent localIntent = new Intent(HWUtil.LOCAL_RECEIVER);
localIntent.addCategory(Intent.CATEGORY_DEFAULT);
localIntent.putExtra(HWUtil.LOCATION, location);
localIntent.putExtra(HWUtil.FROM, HWUtil.LOCATION_SERVICE);
sendBroadcast(localIntent);
}
}
}
}
and i m sending this location updates to Broadcastrecciver
Please note that the continuous usage of pure GPS as location provider is quite energy hungry on mobile devices. Once that is said, I would perform your task as follows:
I would use a (background) service that would be working togheter with your mobile app. I.e., the mobile app will start the execution of this service (check startForeground() functionality so that your service could be run almost with no interruption, and including a notification on statusBar that can be linked to your activity).
The service (or any internal class) would implement the LocationListener interface and will be the one that actually will be sampling locations. Once you get a location you will process it (depending on your requirements you might want to process it in another thread since the default thread of a created service is the same than the Activity UI).
Once processed, youw would deliver the response to the Android activity, i.e., you would call a public method of your activity, or would implement a more complex communication strategy with Handlers, etc.
In regard with the continuous location sampling, I would strongly suggest you to use AlarmManager services so that you could schedule the next readings (you could make it at exact repeating intervals, see official developer's documentation).
If (and only if) the processing of the location update is heavy or time consuming (for instance, you have to transmit it to a server) you could acquire and hold a WakeLock for avoiding the device to fall into sleep mode; do not forget to release the WakeLock after your processing is done, since it is a major cause of energy sinks in mobile apps, so be very careful with this.
Hope it helps for you
AFAIK, wake lock is the easiest way to do. PowerManager.WakeLock
wake lock is a mechanism to indicate that your application needs to have the device stay on.
Any application using a WakeLock must request the android.permission.WAKE_LOCK permission in an element of the application's manifest. Obtain a wake lock by calling newWakeLock(int, String).
Call acquire() to acquire the wake lock and force the device to stay on at the level that was requested when the wake lock was created.
You should aquire a wake lock:
//in onCreate of your service
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
cpuWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"gps_service");
cpuWakeLock.acquire();
// Release in onDestroy of your service
if (cpuWakeLock.isHeld())
cpuWakeLock.release();
and add this to your manifest:
https://developer.android.com/reference/android/Manifest.permission.html
Above is good if you need continuous location updates.
I tried to add this code to my project in my MainActivity/onCreate void:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyApp::MyWakelockTag");
wakeLock.acquire();
Then I tested it my tablet. I was working over ~25 mins but then it stopped again. Sending of the location data was stopped. Then I pushed the pwr button of the tablet and the GPS ikon disapeared on the top of the screen and did not come back...

How to make Alarm Manager work when Android 6.0 in Doze mode?

I am a developer of two alarm clock apps on Google Play. I am trying to get them to work with Android 6.0. However, Doze mode makes it so they do not ring. I put them on the white list, I put a foreground notification icon up, I'm not sure what else I can do - when in Doze mode, the the Alarm Manager alarms are still ignored. The Clock app (which is a Google Play rather than AOSP app), however, is different. When the alarm is enabled on the Clock app, "adb deviceidle step" will always read "active" and never "idle", "idle_pending" or anything else.
Is Android cheating here, giving its own app more power, aka. "pulling an apple"? Are all alarm clock apps on Google Play about to become non-functional? Kind of worried here, these are quality apps that each took a year of part-time development time, and are big income sources for me. Any clues on how I could get these to work would be a huge help.
Setting the AlarmManager intent:
Intent intent = new Intent(context, ReceiverAlarm.class);
if (android.os.Build.VERSION.SDK_INT >= 16) {
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
}
amSender = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT); //FLAG_CANCEL_CURRENT seems to be required to prevent a bug where the intent doesn't fire after app reinstall in KitKat
am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, scheduleToTime+1, amSender);
and the ReceiverAlarm class:
public class ReceiverAlarm extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
if (wakeLock == null) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Theme.appTitle);
wakeLock.acquire();
}
X.alarmMaster.startRingingAlarm(true);
}
and the relevant parts of the X.alarmMaster.startRingingAlarm() method:
if (wakeLock == null) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Theme.appTitle);
wakeLock.acquire();
}
if (screenWakeLock == null) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
screenWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, Theme.appTitle+" scr");
screenWakeLock.acquire();
}
Intent alarmIntent = new Intent(Intent.ACTION_VIEW);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
alarmIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
alarmIntent.setClass(context, ActivityAlarmAlarm.class);
context.startActivity(alarmIntent);
Some of the methods have been pasted inline for easier readability.
Doze and App Standby definitely change the behavior in regards to alarms and wakelocks, but they're definitely not the end of the world for you!
Have you tried using the method setAlarmclock() instead of set()?
It's designed specifically for alarm clocks and may be able to cut through doze. There are a few adb commands you can use to manually put a phone into doze or app standby mode: https://developer.android.com/preview/features/power-mgmt.html
If that isn't able to wake your app up, there's the surefire method setExactAndAllowWhileIdle() is designed to wake the phone from doze no matter what. Worst case scenario, you can wake your app up with this method and use the wakeup to schedule the next alarm.
Another page worth a read is this blog post with its flowchart for background work and alarms: https://plus.google.com/+AndroidDevelopers/posts/GdNrQciPwqo
Put the application in whitelist only allows network in doze mode. AlarmManager does not affected by whitelist.
For setExactAndAllowWhileIdle() method please check the below description from SDK. It will not wake the phone from doze.
When the alarm is dispatched, the app will also be added to the
system's temporary whitelist for approximately 10 seconds to allow
that application to acquire further wake locks in which to complete
its work.

Inquiry related to AlarmManager and WakeLocks

I am developing a native android app that run a backup operation every 30 mins.
I am using AlarmManager for this purpose and it works fine. Here is the code I am using to start the alarm:
public static void startSync(Context context) {
alarmIntent = new Intent(context, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0);
manager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// int interval = 3600000;
int interval =30000 ;
manager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), interval, pendingIntent);
ComponentName receiver = new ComponentName(context, SampleBootReceiver.class);
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
Toast.makeText(context, "Sync Started", Toast.LENGTH_SHORT).show();
}
And here is the the on receive method:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
PowerManager pm = (PowerManager) context.getSystemService(context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
wl.acquire();
Intent eventService = new Intent(context, SyncInBackground.class);
context.startService(eventService);
wl.release();
}
}
I noticed that when my device isn't in standby, the operation took 5 seconds (I calculated it programmatically) but when the mobile is in standby mode it took 11 seconds. That's why I used wake_lock before running the backup operation in a background service, in order to make the app takes only 5 seconds.
But I still get the same results if the mobile in standby mode... it still takes 11 seconds and 5 seconds if not in standby mode.
What can I do to make my background service run the repeating alarm in 5 seconds instead of 11 seconds?
The usual mistake: acquiring a wake lock in the OnReceive does nothing. The AlarmManager already holds a wake lock in OnReceive. Your way works out of pure luck, when/if it works. You have to either use a WakefulBroadcastReceiver or use a WakefulIntentService. The WIS will acquire a static wake lock which will be active between OnReceive returning and the service starting.
See my answer here: Wake Lock not working properly for links.
The problem is that context.startService(eventService) is an asynchronous operation which is very likely to return in just a few milliseconds. This means that when you acquire a WakeLock in your onReceive method, you keep it just for a couple of milliseconds and you release before the service starts.
A way to solve this is to share the a wakelock between your BroadcastReceiver and the service that you're trying to launch. This is how the WakefulIntentService works but you can also do this yourself, for example, by creating a singleton WakelockManager with two methods, one for acquiring and one for releasing a wakelock, then have you BroadcastReceiver call the former and your service call the latter.
Also, remember that leaking wakelocks (by acquiring one but forgetting to release it) can have serious consequences in terms of battery usage.

PowerManager and PARTIAL_WAKE_LOCK behaviour

I use an alarm to take pictures at regular time intervals. I use a BroadcastReceiver as follows:
#Override
public void onReceive(Context context, Intent intent)
{
Log.d(TAG, "Capturing pic");
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CAPPIC");
wl.acquire();
capturePicture();
wl.release();
}
The capturePicture() calls Camera.takePicture(...) and then ends. Finally, as you can see, wl.release() is invoked.
Now, the problem is that the call back of the takePicture is very time consuming in my case. In fact, it performs some manipulations on the picture just taken that can take up to 5 seconds on my device.
My question is, since wl.release() is called while the computational intensive task into the takePicture callback is running, is there any side effect? That is, suppose that the device is in standby mode. The alarm starts --> wakelock is activated --> picture is taken and manipulated but in the meanwhile of the computation wakelock is released... is it safe or there is the risk that the device returns to its standby mode before the routines into the takePicture callback ends?
Your setup is wrong in that you should not be doing a lot in the receiver and in that the AlarmManager holds a wakelock while onReceive() runs anyway - and yes you should not release the wakelock while editing. You should delegate to a service and for reasons detailed here this must be a WakefulIntentService. Now in that service you should set up a mechanism for waiting for the processing to finish - maybe using CountDownLatch.

Categories

Resources