In my application I need to know when device is locked (on HTC's it looks like short press on "power" button). So the question is: which event is triggered when device is locked? Or device is going to sleep?
You should extend BroadcastReceiver and implement onReceive, like this:
public class YourBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_OFF.equalsIgnoreCase(intent.getAction())) {
//screen has been switched off!
}
}
}
Then you just have to register it and you'll start receiving events when the screen is switched off:
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
appBroadcastReceiver = new AppBroadcastReceiver(yourActivity);
registerReceiver(appBroadcastReceiver, filter);
There is a better way:
KeyguardManager myKM = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
if( myKM.inKeyguardRestrictedInputMode()) {
//it is locked
} else {
//it is not locked
}
In addition to the above answer, in-case you want to trigger some action when your app is at the foreground:
You could use the event called onResume() to trigger your own function when your app takes the spotlight from a previously resting state, i.e, if your app was at the background(paused/minimized...)
protected void onResume()
{
super.onResume();
//call user-defined function here
}
Related
I have an Activity (Activity_RingAlarm) that is supposed to be launched as a full-screen intent when an alarm rings. The activity is launched fine, no issue there. I want to give the user an option to dismiss the alarm by pressing the power button. To this effect, I had programmed the Activity to listen to Power button press, as well as the Intent.ACTION_SCREEN_OFF broadcast. The relevant portion of code is shown below:
public class Activity_RingAlarm extends AppCompatActivity implements View.OnClickListener {
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (Objects.equals(intent.getAction(), Intent.ACTION_SCREEN_OFF)) {
DisplayManager displayManager = (DisplayManager) context.getSystemService(DISPLAY_SERVICE);
for (Display display : displayManager.getDisplays()) {
if (display.getState() == Display.STATE_OFF) {
onPowerButtonPressed();
}
}
}
}
};
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setTurnScreenOn(true);
setShowWhenLocked(true);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ringalarm);
// other codes here
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(broadcastReceiver, intentFilter);
}
#Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.e(getClass().getSimpleName(), "keycode = " + keyCode);
if (keyCode == KeyEvent.KEYCODE_POWER) {
onPowerButtonPressed();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
The issue is, while onKeyDown(int, KeyEvent) responds to volume up and down buttons, it does not respond to the power key. Neither in the emulator, nor in my Samsung Galaxy M31 (both running Android 12 API 31).
I tried putting the above code in the main activity of the app, but even there, the issue is the same.
According to answers posted to this question, it is indeed not possible to capture key events related to the power key, but the ACTION_SCREEN_OFF broadcast should still work. But my app doesn't even get that broadcast. The documentation of the above intent action says that the broadcast has nothing to do with the screen turning off, and is broadcasted when the device becomes non-interactive.
In another question (can't re-locate it at the moment), it was said that dispatchKeyEvent(KeyEvent) should work. I tried that too, but it doesn't.
What can I do in this situation?
What I think happens is the activity is destroyed after you press the power button and the broadcast receiver is unregistered before the screen intents have the chance to arrive. What you could do is change the broadcast receiver to be a top level class and unregister it at a moment that is farther after activity destruction: after a screen intent (ACTION_SCREEN_OFF) is delivered to onReceive, after the alarm is dismissed and/or after a time passes from the activity destruction.
You could also try (if you haven't already) eliminating the window flags from the activity to see if they prevent the intents from being delivered to onReceive().
For debugging consider logging when the receiver is registered/unregistered, all intents delivered to onReceive and adding
Intent.ACTION_USER_PRESENT to the IntentFilter.
The problem is that if my app is running and the device (screen) is locked, the app is restarted while the device is locked (I know because I can hear the sound of my app at startup).
[Edit]
This seems very complicated. I think it would be easier to turn off sounds in the app, but I do not know how to do this only when the device is asleep:
public void playSound(int id){
if(!DEVICE_IS_ASLEEP())
snds[id].play(soundID[id], 1, 1, 0, 0, 1);
}
you may registerReceiver using Context (probably inside Service)
//assuming user starting Service by press smth in app (or simple open it), so the screen will be on for sure
boolean screenOn=true;
//put this inside your onCreate
private void initBroadcasts(){
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
//new feature from API 17 - screensaver (?)
if(android.os.Build.VERSION.SDK_INT>=17){
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
}
screenOn = getScreenUnlocked();
this.registerReceiver(screenBroadcastReceiver, filter);
}
screenBroadcastReceiver is a BroadcastReceiver as below:
private BroadcastReceiver screenBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent myIntent) {
if(myIntent.getAction().equals(Intent.ACTION_SCREEN_ON))
screenOn=getScreenUnlocked();
else if(myIntent.getAction().equals(Intent.ACTION_SCREEN_OFF))
screenOn=false;
else if(myIntent.getAction().equals(Intent.ACTION_USER_PRESENT))
screenOn=true;
else if(android.os.Build.VERSION.SDK_INT>=17){
if(myIntent.getAction().equals(Intent.ACTION_DREAMING_STARTED))
screenOn=false;
else if(myIntent.getAction().equals(Intent.ACTION_DREAMING_STOPPED))
screenOn=getScreenUnlocked();
}
}
};
check if screen is unlocked:
private boolean getScreenUnlocked(){
KeyguardManager kgMgr =
(KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
return !kgMgr.inKeyguardRestrictedInputMode();
}
When configuration changes happens with app like screen lock, the activity is restarted. You will get so many answers on stackoverflow to avoid this problem like this; but according to Google Engineers, it is bad practice to retain the activity. You will get the proper answer about how to avoid this problem here
How can I check from a Service if the KeyGuard (Lockscreen) is visible? I want to support the original and custom Lockscreens.
The screen locks only when the device turns the screen off.
You should extend BroadcastReceiver and implement onReceive, like this:
public class YourBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_SCREEN_OFF.equalsIgnoreCase(intent.getAction())) {
//screen has been switched off!
}
}
}
Then you just have to register it and you'll start receiving events when the screen is switched off:
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
appBroadcastReceiver = new AppBroadcastReceiver(yourActivity);
registerReceiver(appBroadcastReceiver, filter);
There is an edge case where users have their device set to lock n seconds after the screen goes off, you might want to add a check in your broadcast receiver for the ACTION_SCREEN_ON and check the time between them.
I built a custom lock screen app that uses a broadcast receiver and service to listen for when the user turns on or off the screen and from there launch my activity. The activity is supposed to completely replace the lock screen. In order to do this my app is supposed to disable the android stock lock so that my app can function as the new lock screen.
Instead what happens is once the application is first installed the the service first started the application appears to be working. and when the user first turns off the screen of their phone when they turn it back on they are presented with my app running on top and is able to unlock their phone with my app. But then once inside the android OS if the user presses the home button the next time they turn off the screen and turn it back on instead of being brought back to my application they are brought to the stock unlock screen with my application open underneath it, when it should be on top.
Here is my code:
My Service:
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.d("MyService","Service STARTED");
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
final BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
}
}
My broadcast receiver:
public class ScreenReceiver extends BroadcastReceiver {
public static ArrayList<String> runningApplications = new ArrayList<String>();
private Context ctext;
public static boolean screenIsLocked;
public static KeyguardManager keyguardManager;
public static KeyguardLock lock;
#Override
public void onReceive(final Context context, final Intent intent) {
ctext = context;
keyguardManager = (KeyguardManager)ctext.getSystemService(Activity.KEYGUARD_SERVICE);
lock = keyguardManager.newKeyguardLock(Context.KEYGUARD_SERVICE);
lock.disableKeyguard();
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenIsLocked = true;
Log.d("ScreenReceiver", "False");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenIsLocked = false;
Log.d("ScreenReceiver", "True");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
}
}
My activity that is started is basically empty with just one unlock button that calls finish(); when pressed.
The behavior of keyguard-related logic can vary from device to device. That's because lockscreens are often custom-made by device manufacturers (i.e. not stock), some of them respect the keyguard logic you use, some don't.
Also, afaik the newer way to control keyguard is to use window flags:
// inside activity
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
This will not solve the problem though, devices still have their say about this.
E.g. from my experience, Galaxy Nexus will show your activity's window above keyguard but will not dismiss it (you'd think Google-branded device should respect the flag, eh), so if you hit the back button in your activity - you'll get standard lockscreen --- while HTC One X seems to handle the dismiss part properly: your activity window will cause standard lockscreen to get dismissed as expected.
I found no way to force all devices to behave properly. Android API is not meant to enable you to create custom lock screens (at least not currently). Take a look at the ones in the store - they all have the exact same problem of not being stable enough.
As Dianne Hackborn says in this Google Groups answer, anything you can do in this regard is a hack so expect it to break from time to time.
I tried to compile your code and got the same error you were talking about. I tried to modify it to make it to work and finally got the problem!!!
public class ScreenReceiver extends BroadcastReceiver {
public static ArrayList<String> runningApplications = new ArrayList<String>();
private Context ctext;
public static boolean screenIsLocked;
public static KeyguardManager keyguardManager;
public static KeyguardLock lock;
#Override
public void onReceive(final Context context, final Intent intent) {
ctext = context;
keyguardManager = (KeyguardManager)ctext.getSystemService(Activity.KEYGUARD_SERVICE);
lock = keyguardManager.newKeyguardLock(Context.KEYGUARD_SERVICE);
lock.disableKeyguard();
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenIsLocked = true;
Log.d("ScreenReceiver", "False");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenIsLocked = false;
Log.d("ScreenReceiver", "True");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
}
}
With this change to the broadcast receiver class I was able to overcome the problem
Try it and tell me if there is any problem.
EDIT:I think the problem might lie in the finish() method....Android dumps apps when it requires memory...I think finish() might be helping android in trashing the app(and this might be the reason why your problem occurs randomly)
I essentially want to display a screen whenever the screen is unlocked regardless of the application already running.
Can someone just tell me how to display text as soon as the phone gets unlocked. I can take it from then on.
I have the following code up till now which I found on the net....
Suppose I want to display abc.xml as soon as the phone gets unlocked. How will i add it in the ScreenReceiver Class ?
Also I do not want to set any screen when the application runs.Do I need to run the code below as service ?
public class SampleActivity extends Activity {
//Declare the necessary variables
private BroadcastReceiver mReceiver;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public void onDestroy()
{
super.onDestroy();
Log.v("$$$$$$", "In Method: onDestroy()");
if (mReceiver != null)
{
unregisterReceiver(mReceiver);
mReceiver = null;
}
}
}
where the Screen Reciever class is as follows
public class ScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
Log.v("$$$$$$", "In Method: ACTION_SCREEN_OFF");
// onPause() will be called.
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
Log.v("$$$$$$", "In Method: ACTION_SCREEN_ON");
//onResume() will be called.
// Better check for whether the screen was already locked
//if locked, do not take any resuming action in onResume()
//Suggest you, not to take any resuming action here.
}
else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT))
{
Log.v("$$$$$$", "In Method: ACTION_USER_PRESENT");
// Handle resuming events
}
}
}
For one, you don't display abc.xml, you display an activity, dialog, or other UI component. You can set up a broadcast receiver that listens for the ACTION_BOOT_COMPLETED intent. Once the device boot completes, you can start a sticky service to listen for the actions you have above. Presumably you'll want to display abc.xml in an activity, so you'll need to fire startActivity from one of the if() blocks above.