Im building a custom home screen with a custom lockscreen.
When the screen turn off, I launch the lock screen (activity),
However, when the lock screen is killed (by "finish()"), it goes back to
the last activity in my homescreen apk, and not to the real activity (apk) that
was visible right before the screen went off.
For example, if i'm in Calculator application, or in Clock applicaiton, And the lock screen turns on, When the lock screen activity is finished, It doesn't return to Calculator/Clock
Here's where I register the lock screen (in the main launcher activity) for receiving screen on/off events:
private void doLockScreenOperations()
{
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
KeyguardLock lock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
lock.disableKeyguard();
IntentFilter lockfiFilter = new IntentFilter();
lockfiFilter.addAction(Intent.ACTION_SCREEN_OFF);
lockfiFilter.addAction(Intent.ACTION_SCREEN_ON);
getApplicationContext().registerReceiver(new LockScreenReceiver(), lockfiFilter);
}
Here's the receiver itself, where I launch the lock screen's activity:
public class LockScreenReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if (action.equals(Intent.ACTION_SCREEN_OFF))
{
if (LockScreenActivity.isLockScreenAlive == false)
{
Intent lockIntent = new Intent(context, LockScreenActivity.class);
lockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(lockIntent);
}
}
else if (action.equals(Intent.ACTION_SCREEN_ON))
{
}
}
}
The LockScreenActivity is, at that moment, a simple activity with a button
that is called finish() when the button is clicked.
I have no idea how to fix this.
Thanks in advance!
I'm not entirely sure mate, but you have to consider this:
Intent.FLAG_ACTIVITY_NEW_TASK starts a fresh new group of views
so logically you don't have a previous activity to go back to when exiting your lock screen.
I'm building one myself, very similarly to how you do it actually.
but unfortunately having these problems:
-it loads to slow sometimes
-it loads whenever it "feels" like :/
nm, goodluck mate
Related
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
I am creating simple widget for contact management, which allows user to dial and send sms to desired contact.
It works fine as "normal widget", but when I add it as lockscreen widget on Android 4.2, sms app or dial app does not start.
Well in fact they star, but "behind" lockscreen, so user still must manually unlock screen to be able to dial/send sms.
I searched web for some solution, but nothing come in handy.
I' am aware of FLAG_DISABLE_KEYGUARD or FLAG_SHOW_WHEN_LOCKED, but since sms/dial apps are not "mine" so i dont know if they set up proper flag.
As a workaround i tried to create my activity which set those flag and then simply starts desired one (dial or sms), but this does not help.
There is a way to unlock screen, but this involves using KeyguardManager and KeyguardLock (which work fine), but in a result of using KeyguardLock.newKeyguardLock() I end up with phone not being able to turn lock automatically, surely because I do not release this lock (it causes lock to appear again, which is not what i want).
In fact, this widget should work simmilarly to default sms widget or mail widget on lock screen?
So, my question is, how to achieve that and start new activity from lockscreen?
Well, i found solution myself. it turned out i was close :)
To launch 3rd party app/activity, simplest solution is to create some kind of proxy activity, which will set proper flags on window and then launches desired activity and FINISHES.
sample code is shown below:
calling intent in widget (calling proxy):
#Override
public void onReceive(Context context, Intent intent) {
Utilities.printLog(TAG, "onReceive");
Utilities.printLog(TAG, "intent: " + intent);
if (intent.getAction().equals(ACTION)) {
final String number = intent.getStringExtra(EXTRAS);
Toast.makeText(context, "Selected number: " + number,
Toast.LENGTH_SHORT)
.show();
/** REMOVING KEYGUARD RECEIVER **/
// not really an option - lock is still holded by widget and screen
// cannot be locked again ;(
// KeyguardManager keyguardManager = (KeyguardManager) context
// .getSystemService(Context.KEYGUARD_SERVICE);
// KeyguardLock lock = keyguardManager
// .newKeyguardLock(Context.KEYGUARD_SERVICE);
// lock.disableKeyguard();
final Intent activity = new Intent(context, MainActivity.class);
activity.putExtras(intent.getExtras());
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
activity.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(activity);
}
super.onReceive(context, intent);
}
in proxy activity just call:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
final Intent callingIntent = getIntent();
final String actionToLaunch = callingIntent.getStringExtra(ContactsStackWidgetProvider.ACTION);
final String number = callingIntent.getStringExtra(ContactsStackWidgetProvider.EXTRAS);
final Intent activity = new Intent();
if (actionToLaunch.equals(Intent.ACTION_DIAL)) {
activity.setAction(Intent.ACTION_DIAL);
activity.setData(Uri.parse("tel:"+number));
} else if (actionToLaunch.equals(Intent.ACTION_SENDTO)) {
activity.setAction(Intent.ACTION_SENDTO);
activity.setData(Uri.parse("sms:"+number));
} else {
throw new IllegalArgumentException("Unrecognized action: "
+ actionToLaunch);
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(activity);
finish();//it is important to finish, but after a small delay
}
}, 50L);
}
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)
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
}
I have read threads on the matter but all of them were regarding launching an activity WHEN the screen is locked or when it is unlocked. However, I need for my program to launch a new activity regardless of the screen being locked or not.
I am using gps and proximity alerts to check when a destination has been reached.
My activity registers a ProximityAlertReceiver such that:
private class ProximityAlertReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String key = LocationManager.KEY_PROXIMITY_ENTERING;
Boolean entering = intent.getBooleanExtra(key, false);
if (entering) {
System.out.println("You have entered the proximity area");
} else {
System.out.println("You have exited the proximity area");
}
Bundle bundle = intent.getExtras();
int status = bundle.getInt("status");
Intent i = new Intent();
i.setClass(context, MEcheScreen.class);
Bundle bundle1 = new Bundle();
bundle1.putInt("status", status);
i.putExtras(bundle1);
i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(i);
}
}
So, when I a proximity alert fires, a new activity will be started.
I am using the public void onNewIntent(Intent newIntent) {} method to handle when the new activity is launched.
So, the problem is, when the screen is locked and a proximity alert is fired, the Intent in the ProximityAlertReceiver class does not get started.
I tried to use the keyguardmanager to disable the keyguard. However, after it has been disabled, it returns to the main screen of the program, but the activity is still not started until I press a button or tap the screen.
Maybe you should fire a notification instead (with sounds and flashing lights even if necessary) from which the activity can be launched IF wanted by the user, which would seem the right thing to do..
a couple of things are needed ...
in your reciever add the following when launching the activity
intenet.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
in the onCreate of the activity add
KeyguardManager mKeyGuardManager = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);
KeyguardLock mLock = mKeyGuardManager.newKeyguardLock("name of my app");
mLock.disableKeyguard();
this works for me in an app that is lauched at device startup
I also then mess with
Settings.System.getInt(cr,Settings.System.SCREEN_OFF_TIMEOUT,0);
but that is another story