Android using a Wake Lock with Foreground service? - android

I'm working on an audio app utilizing exoplayer in a foreground service to allow the audio to play with the screen off. This appears to work as intended, but somewhere I read something about adding Wake Locks.
Is that something that would be necessary with a foreground service? The Wake Lock is used to keep the CPU awake, but the foreground service seems to do that while the service is playing.
I decided to test it on the way to work and it played audio with the screen off for +20 minutes without problems. I assume ~20 mins would be long enough for the OS to shut something down without a wake lock.

Yes, Wake lock is used when you start the service again after the device has been rebooted or when the service is killed.
Use it like this:
Create BroadcastReceiver for receiving the broadcast to start a service.
public class AutoStart extends BroadcastReceiver {
LocalReceiver localReceiver = new LocalReceiver();
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent intent2 = new Intent(context, YourService.class);
if (Build.VERSION.SDK_INT >= 26)
context.startForegroundService(intent2);
else
context.startService(intent2);
localReceiver.startMainService(context); //It will create a receiver to receive the broadcast & start your service in it's `onReceive()`.
}
}
}
Register that receiver in the Manifest with ACTION_BOOT_COMPLETED intent-filter.
<receiver android:name="com.demo.service.service_manager.AutoStart">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
Now we have created the receiver which will receive a broadcast only one time when the device is rebooted. So we have to use wakelock manager to keep the register our service within a limited time.
Now, create the broadcast receiver which will be used to receive the broadcast to start the service.
public class LocalReceiver extends BroadcastReceiver {
PowerManager.WakeLock wakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).wakeLock(PowerManager.PARTIAL_WAKE_LOCK, ":YourService");
wakeLock.acquire(60 * 1L); //It will keep the device awake & register the service within 1 minute time duration.
context.getPackageManager().setComponentEnabledSetting(new ComponentName(context, YourService.class), 1, 1);
playMusic(); //Play your audio here.
wakeLock.release(); //Don't forget to add this line when using the wakelock
}
Now create a method in LocalReceiver to send the broadcast to start the service.
public void startMainService(Context context) {
PendingIntent broadcast = PendingIntent.getBroadcast(context, REQUEST_CODE, new Intent(context, LocalReceiver.class), 0);
}
That's it! We've successfully implemented the wake lock. Now, whenever you want to play a sound. Just send the broadcast to the LocalReceiver & it will get your job done.
Also, don't forget to register this receiver in the Manifest as well as add android:enabled="true" and android:exported="true" where you register your service in Manifest.
<receiver android:name="com.demo.service.service_manager.LocalReceiver">
NOTE : We have used playMusic() inside the onReceive(). So it will also play the audio when the device is rebooted & the service will be registered. If you just want to bind the service on reboot, then you can simply add startService() method inside the onReceive() instead of the playMusic().

Related

Launch Activity on AlarmManager event from broadcast receiver

I have am alarm manager through which i set a time to trigger on it by providing a broadcast receiver, onReceive method of broadcast receiver calls successfully but any idea how to launch app from onReceive if app is not running in foreground?
Menifest
<receiver
android:exported="true"
android:name=".AlarmReceiver" />
BroadcastReceiver
#Override
public void onReceive(Context context, Intent intent)
{
Intent scheduledIntent = new Intent(context, MainActivity.class);
scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(scheduledIntent);
}
MainActivity
AlarmManager alarmManager=(AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent intent=new Intent(this,AlarmReceiver.class);
PendingIntent pendingIntent=PendingIntent.getBroadcast(this,1000,intent,0);
alarmManager.set(AlarmManager.RTC_WAKEUP,timeInMillis,pendingIntent);
Kindly help
Thanks
It is basically a radio music stream using exoplayer , what we need is user set a time on which he want it to play , and when that time comes stream start playing automatically .
A background service will only run for one minute on Android 8.0+. For a music player, you will want a foreground service, where the associated Notification gives the user playback controls (e.g., pause, resume, stop).
First, you should use workManager
Also, Brodcastreciver has limits on different android versions doc

BroadcastReceiver dies with app

If i let the phone sit for a long time like 15 minutes i lose my receiver but i thought it was to persist like a service after being killed for memory.
Manifest:
<receiver
android:name=".WearableReceiver"
android:enabled="false">
<intent-filter>
<action android:name="com.example.johnbravado.MESSAGE_PROCESSED"/>
</intent-filter>
</receiver>
In Activity to start receiver
ComponentName component = new ComponentName(CounterActivity.this, WearableReceiver.class);
getPackageManager()
.setComponentEnabledSetting(component,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
The receiver
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
//MyConstants.getInstance().showToast("Message Rcvd");
PowerManager powerManager = (PowerManager) context.getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"com.example.johnbravado");
wakeLock.acquire();
// Do Work
MyConstants.getInstance().msgReqAction(intent.getIntExtra(MyConstants.BROADCAST_DATA_REQ, 0));
wakeLock.release();
}
The broadcast sender
String BROADCAST_ACTION_RESP = "com.example.johnbravado.MESSAGE_PROCESSED"
#Override
public void onMessageReceived(final MessageEvent messageEvent) {
nodeId = messageEvent.getSourceNodeId();
String incomingPath = messageEvent.getPath();
int incomingReq = Integer.parseInt(new String(messageEvent.getData()));
if(incomingPath.equalsIgnoreCase(MyConstants.MSG_COUNTER_REQ_PATH)) {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(BROADCAST_ACTION_RESP);
broadcastIntent.putExtra(MyConstants.BROADCAST_DATA_REQ, incomingReq);
sendBroadcast(broadcastIntent);
}else if(incomingPath.equalsIgnoreCase(MyConstants.MSG_DEFAULT_PATH)){
}
}
only way I get this to persist for long periods of time is to invoke a service
wearableReceiverIntent = new Intent(this, WearableReceiverService.class);
if(!WearableReceiverService.isRunning())
startService(wearableReceiverIntent);
the service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Let it continue running until it is stopped.
IntentFilter filter = new IntentFilter(MyConstants.BROADCAST_ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new WearableReceiver();
registerReceiver(receiver, filter);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_notif_bible)
.setContentText("Preaching").build();
startForeground(MyConstants.NOTIF_COUNTING_SERVICE, notification);
isRunning = true;
return START_STICKY;
}
If I run the service it persists for long periods of time but it drains the battery unnecessarily considering I interact only once every 10 minutes. I was under impression Broadcast receiver would work like service except for short bursts of work. invoke the service if you need to do long actions.
A BroadcastReceiver handles an intent and then stops again. This handling of an intent should be fast. If you want to do a lot of stuff, you should start an Service from the BroadcastReceiver and handle it from there.
A BroadcastReceiver object is only valid for the duration of the call
to onReceive(Context, Intent). Once your code returns from this
function, the system considers the object to be finished and no longer
active.
A BroadcastReceiver is started using the sendBroadcast intent.
So remove android:enabled="false" and use sendBroadcast, which will startup the Receiver by Android.
http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html
Greenify was killing my app when the screen went off. I was battling something I had no hope of defending against with code. After I explicitly told Greenify to not kill my app, I never told it to kill my app to begin with, everything worked as intended.
I had the same problem due on my Asus ZenPad due to the Asus Mobile Manager app, specifically the "Auto start manager" was blocking the intent to my app.
Deactivating the app (uninstall is not possible) worth nothing, the solution has been to leave the app installed but whitelist my developing app so it can receive broadcast like PACKAGE_REPLACE. (Pay attention that the switches are confusing, you actually have to touch on "blocked" so it turns on into "allowed" to enable it.
I think another option is to update or change the ROM (choosing one without all that bloatware).
If your BroadcastReceiver is setup in your manifest, there is no need to try and adjust the PackageManager component information for your package. As long as you remove the enabled="false" part.
Your BroadcastReceiver should be very short with what it does: typically update some internal data or start another component which can do the heavy lifting of your app's operation. You can use it to trigger a Service to do this type of thing in the background. But, note that "background" in this case means without user-interaction. It does not mean a background context of execution, such as a secondary thread. It is up to you do manage the thread(s) in your Service. Your BroadcastReceiver and Service callback entry points (onReceive() and onStartIntent()) run in the context of the main thread of your app.
Power management definitely plays a roll in all of this. Is your broadcast Intent actually being sent and done in a way which will wake the device? If it does wake the device and send the Intent, the device will only stay awake long enough for the BroadcastReceiver to run its onReceive(); after that returns there are no guarantees. The device will aggressively sleep, which is why wakelocks are a thing. However, use of wakelocks can cause excessive battery drain, unless used properly. If you are running on Marshmallow or newer, the Doze functionality can also wreck havoc on your plans. Wakelocks are ignored when in Doze mode and won't be considered until the user brings the device out of doze.
I had the same issue and it was resolved by granting auto launch permission for the app.
Go to
Settings->Permissions->Manage Auto Launch
and allow auto launch for your app.

Screen ON/OFF receiver in android [duplicate]

I was just wondering if it is possible to register a broadcast receiver that detects Screen ON/OFF in the application manifest.
The reason why I don't like the programmable method is that it requires the app to be running in order to detect such a thing, while:
"Applications with Broadcast Receivers registered in the manifest don’t have to be running when the Intent is broadcast for the receivers to execute" (source: Professional Android 2 Application Development book)
My app is actually a lockscreen app which by using the programmable way needs to be running all the time :S
Is there a way around it?
I'm trying the following in the manifest:
<receiver android:name=".MyBroadCastReciever">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
and simple MyBroadCastReciever class:
public class MyBroadCastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.i("Check","Screen went OFF");
Toast.makeText(context, "screen OFF",Toast.LENGTH_LONG).show();
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Log.i("Check","Screen went ON");
Toast.makeText(context, "screen ON",Toast.LENGTH_LONG).show();
}
}
}
The two actions for screen on and off are:
android.intent.action.SCREEN_OFF
android.intent.action.SCREEN_ON
But if you register a receiver for these broadcasts in a manifest, then the receiver will not receive these broadcasts.
For this problem, you have to create a long running service, which is registering a local broadcast receiver for these intents. If you do this way, then your app will look for screen off only when your service is running which won't irritate user.
PS: start the service in foreground to make it running longer.
A simple code snippet will be something like this:
IntentFilter screenStateFilter = new IntentFilter();
screenStateFilter.addAction(Intent.ACTION_SCREEN_ON);
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(mScreenStateReceiver, screenStateFilter);
Don't forget to unregister the receiver in the Service's onDestroy:
unregisterReceiver(mScreenStateReceiver);
Just in case for people who are asking why the receiver does not work with the declare broadcasts in manifest for ACTION_SCREEN_ON and ACTION_SCREEN_OFF:
https://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_ON https://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_OFF
You cannot receive this through components declared in manifests, only
by explicitly registering for it with Context.registerReceiver().
This is a protected intent that can only be sent by the system.
You need to create a background service to check for it. Then you can set it programmatically.

Broadcast receiver works only when device reboot android

Hi I am developing android application in which I am defining one broadcast receiver.I am calling receiver from my activity. I am defining broadcast receiver like this :
public class MyScheduleReceiver extends BroadcastReceiver {
private static final long REPEAT_TIME = 100 * 5;
#Override
public void onReceive(Context context, Intent intent) {
Log.i("RRRRRRRRRRRRRRRRRRRRRRRR", "on receive");
}
}
In android manifest file I am defining like this:
<receiver android:name="abc.xyz.MyScheduleReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
and in main activity I am calling my broadcast receiver like this :
//in activity oncreate
startService(new Intent(this, MyScheduleReceiver.class));
My problem is that when call start service it's not starting my service actually. But when i restart my device it start my service because I gave intent filter "BOOT_COMPLETED". what I wanted to do actually when i call start service my service must be start,
Am I doing something wrong. How to solve this problem?
Actual what happens here is that you can staring a broadcast receiver while starting the activity and this broadcast receiver starts listening BOOT_COMPLEATED is happening or not. When this happens it comes to onreceive . If you need to start a process doing in background you can use a a Service insted of BroadcastReciever. BroadcastRecievers are used to listen for some events to happen.Go through this, it will help you
Services
BroadcastReceiver
You're either confused, or you aren't wording your question well. What you have in your manifest (and how Android works generally) is that when BOOT_COMPLETED occurs, it will call that BroadcastReceiver you defined. It will not automatically start an activity or service. If you want to do that, you need to call startService or startActivity in your onReceive function of the receiver.
You do not start BroadcastReceivers. You start services, which are long term background processes. You register BroadcastReceivers to be informed of special events (like BOOT_COMPLETED). When one of the events you registered for occurs, it will create an instance of that class and call its onReceive.
Hopefully that clears things up. If not, I suggest you reread some tutorials on services and broadcast receivers, you seem to have the two confused.
startService call would only start a Service. MyScheduleReceiver here is a braodcast receiver. To trigger broadcast receivers, you generally have to send broadcasts and not call the startService.
to start broadcasts you need to send broadcasts not startService()
add this instead of startService(new Intent(this, MyScheduleReceiver.class));
Intent intent = new Intent();
intent.setAction("pakagename.MyScheduleReceiver");
sendBroadcast(intent);
I hope it helps.

How to save scheduled alarm after app was killed by Android or task killer?

Code that schedules alarm.
PendingIntent sender = PendingIntent.getBroadcast(this, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, time, sender);
Its working fine, but when I kill my app in task killer, I lost my scheduleed alarm. How to solve this problem?
have your application broadcast a message as its being killed, and when this message is broadcast, then have a listener check if the service is still running.. if its not run it. This will insure that your service is running even if the application is killed.
Update
I'll try to create a flow diagram for you
The onDestroy() method is part of a service.
I hope this helps.
UPDATE 2
One thing I forgot to mention is the fact that you ideally only want one instance of the service to be run. So just looking at the ID that is present within the onStart() should be == to 1 to start it else.. ignore it.
Methods of notice of the Service Class:
onStart() : This method is called when the service is being started
onDestroy() : This is the method that is called when a service is being killed
Methods of notice of the BroadcastReciever class:
onReceive(): This methods receives all intents that are sent to it (unless filtered)
Look up examples on BroadcastRecievers (Message Broadcasting) and Service (Starting a service)
References:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
http://developer.android.com/reference/android/app/Service.html
Alarm set by alarm manager is not killed when app is closed, how ever when a reboot occurs all alarms are cleared by the os since there is no persistence. So you need to do the persistence.
Every Time while setting a alarm save the alarm time.
Register a receiver for boot completion.
Set the alarm again on reboot.
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//re register the alarm
}
}
Manifest.xml
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
.......
<receiver
android:name="BootReceiver"
android:enabled="true"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
You could use SharedPreference to save the time (time at when the alarm should be triggered or time at when it should be triggered next)
Use that to set a new alarm at the boot receiver.

Categories

Resources