Is there a way to detect when a user unlocks the phone? I know about ACTION_SCREEN_ON and ACTION_SCREEN_OFF, but these seem to be fired when the screen switches on/off when pressing the power button, but not actually when the phone gets unlocked when pressing the Menu button...
I am trying to detect the unlock/lock while an activity is running, and I want to resume the activity once unlocked.
Here's what to do:
Say you want to detect the unlock event and do something in your activity when the phone is unlocked. Have a Broadcast Receiver for ACTION_SCREEN_ON, ACTION_SCREEN_OFF and ACTION_USER_PRESENT.
onResume of the activity will be called when ACTION_SCREEN_ON is fired. Create a handler and wait for ACTION_USER_PRESENT. When it is fired, implement what you want for your activity.
Credit goes to CommonsWare's answer here: Android -- What happens when device is unlocked?
After struggling with this for a while, I've found that the best way to do this is to register a BroadcastReceiver on the "android.intent.action.USER_PRESENT" action.
"Broadcast Action: Sent when the user is present after device wakes up (e.g when the key-guard is gone)."
To distinguish between cases where the user has turned on phone screen when it wasn't locked, and when they actually unlocked it use the KeyguardManager to check the security settings.
Code example:
Add this to your activity:
registerReceiver(new PhoneUnlockedReceiver(), new IntentFilter("android.intent.action.USER_PRESENT"));
Then use this class:
public class PhoneUnlockedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
KeyguardManager keyguardManager = (KeyguardManager)context.getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardManager.isKeyguardSecure()) {
//phone was unlocked, do stuff here
}
}
}
public class PhoneUnlockedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)){
Log.d(TAG, "Phone unlocked");
}else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
Log.d(TAG, "Phone locked");
}
}
}
register receiver by this statement
receiver = new PhoneUnlockedReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_USER_PRESENT);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, filter);
Didn't test it but try the following:
Wait for ACTION_SCREEN_ON.
(After screen is on,) Wait for ACTION_MAIN with category CATEGORY_HOME (Which launches the home screen) - This is probably what is sent after the phone gets unlocked.
The 1st step is needed to filter out regular HOME key presses.
Related
I have a service which launches a "BroadcastReceiver" after the user has finished booting (ACTION_BOOT_COMPLETED) and when the device goes to sleep (ACTION_SCREEN_OFF). My "BroadcastReceiver" checks when an incoming call is received (TelephonyManager.CALL_STATE_RINGING) and launches a "Service" that records the call. It is working but the problem is that my device turn off display during call when I put the phone to my ear, so the service launches again the "BroadcastReceiver". Is there someone who knows how to solve it?
public class MyService extends Service {
private BroadcastReceiver mReceiver;
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mReceiver = new MyReceiver();
registerReceiver(mReceiver, filter);
}
This should'nt be possible, because the telephone app is in the forground and is triggering the display if it detects an proximity near event. You can maybe set a wakelock and release this afterwards.
I registered receiver in onCreate, but onReceive sometimes get called, sometimes not.
public class MyReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.v("receiver","get called");
}
}
Here is how I register receiver in onCreate
PROCESS_RESPONSE = getBaseContext().getResources().getString(R.string.serviceResponse);
IntentFilter filter = new IntentFilter(PROCESS_RESPONSE);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new MyReceiver();
registerReceiver(receiver, filter);
Here is how I send broadcast:
Intent broadcastIntent = new Intent();
PROCESS_RESPONSE=getBaseContext().getResources().getString(R.string.serviceResponse);
broadcastIntent.setAction(PROCESS_RESPONSE);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
Try this:
broadcastIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
The reason it sometimes works and doesn't work is
because Android 3.0 introduced a launch control security measure that prevents components of stopped applications from being launched via an intent. An application is considered to be in a stopped state if the application has either just been installed and not previously launched, or been manually stopped by the user using the application manager on the device. To get around this, however, a flag can be added to the intent before it is sent to indicate that the intent is to be allowed to start a component of a stopped application.
Quote source
So when you try a fresh install (launching from IDE) the application is considered in the stop state for a while, then later is not. So it sometimes doesn't work when you try to broadcast. Let me know if this works, and of course ensure you have registered the BroadcastReciever (I'm sure you have if it works, at least some of the time).
How can I register a BroadcastReceiver listening for the "PACKAGE_ADDED" action programmatically? I am trying to do something after a package is installed. I can get it working by registering the receiver in the AndroidManifest.xml, but I need to get it working the other way by programmatically registering it so that it only gets called on .apks installed through my app. I've tried it several different ways, the code below is from this answer https://stackoverflow.com/a/4805733/1024722 but it doesn't work. Any ideas?
private BroadcastReceiver receiver;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ButterKnife.inject(this);
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.v("test", "received");
}
};
registerReceiver(receiver, intentFilter);
}
EDIT: In my app's activity, I click a button to download the app from the server and then to install it I click the downloaded app in my notification bar. It then presents this screen:
I click "Install" and it installs but doesn't call my onReceive method(unless I register it in the xml). Then it shows this screen:
then I click "done" and it returns to my activity with the "install" button. I am wondering if it's not working because it launches the activities shown in the screenshots, and is therefore not able to call the onReceive method in my receiver since my activity's onPause method has been called and isn't "active" anymore until I click done, which is after the "PACKAGE_ADDED" action gets called.
You need to add the http://developer.android.com/reference/android/content/IntentFilter.html#addDataScheme(java.lang.String):
|intent filter object|.addDataScheme("package");
The PackageManager will only send it to receivers that have that have that intent action AND the data scheme as 'package'.
It sounds like you want to control whether components published in your manifest are active, not dynamically register a receiver (via Context.registerReceiver()) while running.
If so, you can use PackageManager.setComponentEnabledSetting() to control whether these components are active:
http://developer.android.com/reference/android/content/pm/PackageManager.html#setComponentEnabledSetting(android.content.ComponentName, int, int)
Note if you are only interested in receiving a broadcast while you are running, it is better to use registerReceiver(). A receiver component is primarily useful for when you need to make sure your app is launched every time the broadcast is sent.
I have an android application that needs to detect when the screen is going to lock.
is it possible to discover how long the screen will stay "UnLocked" for?
You will need to register a broadcast reciever.Your system will send a brodcast when device is going to sleep. Put the following code wherever desired:
private BroadcastReceiver receiver = new BroadcastReceiver() {
public void onReceive(final Context context, final Intent intent) {
//check if the broadcast is our desired one
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
//here define your method to be executed when screen is going to sleep
}};
you will need to register your receiver:
IntentFilter regFilter = new IntentFilter();
// get device sleep evernt
regFilter .addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, regFilter );
ACTION_SCREEN_OFF is sent after the screen turns off and ACTION_SCREEN_ON is sent after the screen turns on.
UPDATE:
1.Method 1: As far as i know, you can not setup a listener before ur device goes to sleep.There is no such listener inside PowerManager. A solution which comes to my mind is to get the device time out from the settings and then setup a count down timer in your app. The countdown should be reset every time user touches screen. This way you may guess the time when the device goes to sleep and then setup a wakelock before the device goes to sleep and run your desired code and after that,disable the wakelock and the put the device to sleep.
2.Method 2: inPause() method of your activity is called when your device goes to sleep. You might be able to do some code there.Just a thought.
You have to use "Wakelock"..
try this code
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "whatever");wl.acquire();
And don't forget to take permission in your menifest
"android.permission.WAKE_LOCK"
and write wl.release() in your pouse() method..
Alright, so i am having some problems trying to get a broadcast receiver and service to work properly with screen off and screen on.
What i am trying to do is start something when the screen goes off or when the screen goes on. I got it to work from an activity for testing, but the activity must be currently running. I need it to start from the background pretty much.
Now, i know that using the intent filters in the manifest does not work for screen_off and on. How would i be able to do this? I guess this would work sort of like a lockscreen...
Screen off --> starts something (example activity or create a log message as a toast wouldn't work)
Add a receiver:
public class BroadcastReceiverScreenListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Objects.equals(intent.getAction(), Intent.ACTION_SCREEN_OFF)) {
** Do your stuff**
}
}
From the docs:
You cannot receive this through components declared in
manifests, only by explicitly registering for it with
registerReceiver(BroadcastReceiver, IntentFilter)
This is a protected intent that can only be sent
by the system.