Screen ON/OFF receiver in android [duplicate] - android

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.

Related

Android using a Wake Lock with Foreground service?

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().

Not able to get actions to fire USER_PRESENT or SCREEN_ON Android Emulator

I want to know when a user has turned their phone on eg. click the power button/possibly actually unlocked their phone. The ultimate goal is to update a widget's display after calling an API vs. using scheduled updates.
The issue is I've been scouring threads and I have not been able to get my logs to fire in Logcat. I have tried both Receiver and Service methods. Is what Is what I am attempting possible?
I have also tried setting the READ_PHONE_STATE permission in the manifest.
Some code context of what I have:
Manifest:
<receiver android:name=".CustomBroadcastRecveiver">
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT">
<action android:name="android.intent.action.SCREEN_ON">
</intent-filter>
</receiver>
Optional service in manifest that I tried:
<service android:naem=".CustomService"/>
CustomBroadcastReceiver:
public class CustomBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("MyTag", "broadcast receive"); // this does not run
if (intent.getAction().equals(Intent.ACTION_USER_PRESENT) {
Log... // this doesn't run, same for ACTION_SCREEN_ON that would be in a new if block
}
}
}
I'm open to other alternatives. I can provide more context if necessary. I can expand more on my service implementation if that is the way to go assuming what I'm after is possible.
Edit
To add more context on how I used Elletlar's answer
In my MainActivity I added:
private static Context context;
Then inside onCreate:
context = getApplicationContext();
// instantiate my specific receiver
// set the code from answer below
Note: I am API 29 if it makes any difference.
From the "android.intent.action.SCREEN_ON" docs, "You cannot receive this through components declared in manifests, only by explicitly registering for it with
Context#registerReceiver(BroadcastReceiver, IntentFilter).
Example of registering explicitly:
myReceiver = new MyReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(myReceiver, filter);

I want to use broadcast receiver even if the app is closed

I am trying to show a toast message when receiving an incoming call/outgoing call.
The receiver is not working if the app is closed.
I do not want to use Service. Please help me out.
'I am using the below receiver code'
public class CallReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
if (isConnected(context)) {
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) {
Toast.makeText(context, "Call in progress", Toast.LENGTH_LONG).show();
}
}
}
'This is receiver registered in manifest'
<receiver android:name="com.example.android.testapplication.CallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"></action>
<action android:name="android.intent.action.new_outgoing_call"></action>
</intent-filter>
</receiver>
Try adding the phone state permission to your manifest.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
By default when you register a BroadCastReceiver with AndroidOS that means Receiver always work as the Service part even your application is not working, since you do not have to worry about this problem.
I think the problem is the way you register you Receiver was not correct.
With in/out coming call you should use PhoneStateListener which has overrided method onCallStateChanged. You can use 3 states over there.
Maybe this example will be helpful.

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.

Android receivers being ignored when activity is not active

I have a background service which has a receiver for connectivity change which only seems to be received if the activity is active.
#Override
public void onCreate() {
mContext = this;
IntentFilter connectivityChangeFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
registerReceiver(receiver, connectivityChangeFilter);
I've set it up in the manifest as follows:
<service
android:name="com.myservice.TimeService"
android:label="com.myservice.TimeService" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</service>
I have another receiver for boot completed which works ok, which is registered as a receiver in the manifest (unlike this one).
Is the intent filter not enough to run a broadcast? I would want the receiver to call a method on the service so it needs to be able to access methods of the service but I don't think receivers can bind to services.
-- Update
In a nutshell, I want to know if I can statically declare a receiver that interacts with a service. Dynamic declaration works only if the app is active.
Use android sticky intent
A normal broadcast Intent is not available anymore after is was send and processed by the system. If you use the sendStickyBroadcast(Intent) method, the Intent is sticky, meaning the Intent you are sending stays around after the broadcast is complete.
example code here:

Categories

Resources