Activity lifecycle during phone display timeouts - android

Today I noticed something rather interesting. The activity lifecycle seems to have a slight discrepancy when the phone display times out. Let me explain with an example.
I have an activity that uses the accelerometer to vibrate the phone. In the onPause event I unregister the SensorManager listener so that I don't vibrate the phone when my activity is no longer the main focus.
However, I've noticed if the display shuts off and then comes back on my activity has the SensorManager listener registered even before I unlock the screen, enter my password, and my activity is shown.
Now I realize this is my own interpretation of how I would expect it to work, but to me this seems rather strange, since my activity isn't yet the main focus. I expected the SensorManager listener wasn't registered because onResume hasn't yet been called. This clearly isn't the case when I can make my phone vibrate from both the lock screen and the password screen.
So, can anyone explain why this behavior? Secondly what can I do to get around it?
Thank you.
EDIT for clarity
I use the accelerometer to trigger a vibrate by moving the phone. This is accomplished through the SensorManager listener.
Scenario:
My activity is in the foreground (main focus). I trigger the vibrate by moving the phone. The display times out. At this point I can not trigger the vibrate. I press home/power to show the screen. I can now vibrate my phone even though either the lock screen or password screen is shown and my activity is not in the foreground.
I can not verify if the reason I can not vibrate the phone when the display turns off is because onPause was called or there is something inherent to the OS that prevents it. Or to put it another way, I also can't verify if onResume was called when the display turned on.
The key to all this is understanding the activity life cycle when the phones display is shut off. Unfortunately, my expectation was that it would follow the same life cycle diagram that we have all learned. My opinion was that it is different.

You said it.
"expected the SensorManager listener wasn't registered because onResume hasn't yet been called. This clearly isn't the case when I can make my phone vibrate from both the lock screen and the password screen."
onResume is called before you unlock the phone

The following code will handle Screen Off and Screen On intents. Perhaps you can call onPause() in the onResume() called only after the screen turns on, and call and onResume() when your activity has focus again.
public class ExampleActivity extends Activity {
#Override
protected void onCreate() {
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
}
#Override
protected void onPause() {
if (ScreenReceiver.wasScreenOn) {
System.out.println("onPause() called because screen turned off.");
} else {
System.out.println("normal onPause() call");
}
super.onPause();
}
#Override
protected void onResume() {
if (!ScreenReceiver.wasScreenOn) {
System.out.println("onResume() called when screen turns on");
} else {
System.out.println("normal onResume() call");
}
super.onResume();
}
}

Ah. Your edit tells us why this is happening.
The problem is that when your "screen times out" and the phone goes black, what is happening is the phone is actually going to sleep. The OS is probably going into a low power state and turning of listeners for various things and possibly turning off the accelerometer and/or vibrator.
If you really want the activity to be able to vibrate, try holding a wake lock.
http://developer.android.com/reference/android/os/PowerManager.WakeLock.html

Related

Waiting till phone screen gets on

What I want:
I am developing one app where I want to display dialog / popup on incoming call.
I have observed in log that there is slight delay between my activity start on incoming call and phone screen getting on. First activity gets fired and then phone screen gets on.
So I want to display this dialog after the phone screen gets on. In short I want to wait till phone gets on.
What I Tried:
I have used Asynctask in BroadcastReceiver
protected Boolean doInBackground(Void... params) {
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
isScreenOn = powerManager.isInteractive();
return isScreenOn;
}
and followed this answer. But it is giving me compile time exception
unhandled exception java.util.concurrent.executionexception even after searching a lot on google I was not able to solve it. So I used another approach.
I have created another* broadcast receiver for phone screen status as per this link
(*Note I already have incoming call broadcast receiver)
But I am not able to figure out how incoming call broadcast receiver will communicate to phone screen broadcast receiver and wait till phone screen gets on.
I have even tried to add intent action in existing broadcast receiver but again dont know how to wait till phone screen gets on.
Any pointers/suggestions?
After Struggling a lot on this issue, finally able to solve it. Posting the answer if anybody else struggling for similar issue.
case TelephonyManager.CALL_STATE_RINGING: //Incoming Call Ringing
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Calling activity to show dialog / popup window.
}
}, 1000);
It was that simple. Phew!!

Stop listening for fingerprint when screen off

A user of my app reported that when my app is listening for fingerprint authentication (I have called fingerprintManager.authenticate) and the screen is turned off (by hitting the devices power switch button), it is not possible to use the fingerprint to unlock the device.
I can also see that the onAuthenticationError callback method is called when the screen is turned off, which does not happen when I leave my activity, because I call CancellationSignal.cancel() in my onPause method. I have checked that onPause is being called.
The same behavior can be observed in the Fingerprint Dialog sample (https://github.com/xamarin/monodroid-samples/tree/master/android-m/FingerprintDialog, ported from https://github.com/googlesamples/android-FingerprintDialog)
What can I do to resolve this behavior?
EDIT: I also tried to register a broadcast receiver for android.intent.action.SCREEN_OFF which gets notified after onPause, so it's no surprise that calling cancel() in that receiver does not change anything.
My problem is similar to yours: if someone sends my app to background by pressing Home button it still holds control over Fingerprint Sensor, so no one else can use it. Calling cancel from activities onPause() isn't working:
#Override
protected void onPause() {
super.onPause();
/**
* We are cancelling the Fingerprint Authentication
* when application is going to background
*/
if (fingerprintHelper!=null && fingerprintHelper instanceof AndroidFingerprintHelper){
log.info("canceling AndroidFingerprintHelper dialog");
fingerprintHelper.cancelIdentify();
}
}
You need to call the cancel() method of your CancellationSignal in your activity's onPause() method but before super.onPause(). Otherwise you will get the warning
Rejecting your.package.name. ; not in foreground
cancelAuthentication(): reject your package name
I've searched the source code of Android FingerPrint Service and I've found this lines:
public void cancelAuthentication(final IBinder token, String opPackageName) {
if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
return;
}
//we don't get here
...
...
}
where canUseFingerprint is actually checks if we are foreground or no (one of the things it does):
private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) {
if (foregroundOnly && !isForegroundActivity(uid, pid)) {
Slog.v(TAG, "Rejecting " + opPackageName + " ; not in foreground");
return false;
}
//we don't get here
}
This way we can never call cancelAuth from the background. And Android thinks that we are in background right after the super.onPause(); is called. After several hours of research the only solution I've found is to swap the cancel action and the super.onPause() :
#Override
protected void onPause() {
/**
* We are cancelling the Fingerprint Authentication
* when application is going to background
*/
if (fingerprintHelper!=null && fingerprintHelper instanceof AndroidFingerprintHelper){
log.info("canceling AndroidFingerprintHelper dialog");
fingerprintHelper.cancelIdentify();
}
super.onPause();
}
Worked for me on Android M and N. Hope this helps.
I have encountered similar behavior with the Samsung Fingerprint SDK (cannot authenticate when the screen is locked or off, it's not a bug, it's by design). After reviewing this scenario - we have concluded that the best approach would be to create a notification for the user that would contain a PendingIntent that would trigger your app and start the finger print authentication process.
The notification could make the phone vibrate/beep so that the user is alerted.
Hope this helps.
In the callback method onError() also call 'stopListeningc'. Then when screen turn off, the fingerprint listener from your app will stop work, then your device will listen fingerprint.
Hope this help!

android fragments and listener events of activity running in background (lock screen)

I'm working on an installer which has different installation steps running in various fragments and services. If the phone is locked, the installation stops until the lock screen has been resolved, even listener callbacks are waiting for an user input.
I can catch intents from background services, but only with onNewIntent(Intent intent). onResume() is called after an user interaction only.
Is it possible to force an activity to the foreground, even the phone is locked or do I need a different concept on a locked phone?
Regards
Have you tried Service for background process, If you use service then it will available continously ,If phone is lock or not. Do some R & D for Service may be it should help you.
try set android:showOnLockScreen="true" in your activity that need to appear while phone lock.
And try code below at on Activity onCreate() method
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stop_alarm);
Window wind = getWindow();
wind.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
wind.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
wind.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
wind.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
}

How to turn keyguard on in reliable way?

DUPLICATE WARNING: this problem deals with details of Android API, suitable for calling both from some frontend and services, there are many similar threads on SO, but focused only on frontends.
Problem
I would like to turn on keyguard programmatically, so for example user clicks a button in my app and the phone gets locked (to use phone user has to unlock it first).
The catch is -- I would like to find rock-solid way, that works in every valid case.
Attempts
I tried:
lockNow with DevicePolicyManager -- when the screen is off (but phone is not locked) this call is ignored (i.e. the keyguard is not activated)
reenableKeyguard with KeyguardManager.KeyguardLock -- the call to the method is ignored in every possible case
goToSleep with PowerManager -- I cannot call it, because of the problem with permission, it requires DEVICE_POWER despite I already have this permission set
So far I pursue the first way (lockNow) with extra hacks that somehow deal with the case when the screen is off, but it extremely ugly, thus I am hoping there is some straightforward way.
One solution could be using thread on postdelayed handler.
the catch here is, thread will stay alive even after the screen is off, where your application would be under paused state (unless process is killed)
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
keyLock.reenableKeyguard();
Log.i("LOCK","key guard back on");
finish();
}
}, 300);
Another way of doing this would be to use timer task, but timer task might get killed sometimes (don't know for sure, but my past experiences says not sure)
TimerTask Active = new TimerTask() {
#Override
public void run() {
keyLock.reenableKeyguard();
Log.i("LOCK","key guard back on");
finish();
}
};
Timer starter = new Timer();
starter.schedule(Active, 300);
I can't be 100% sure this is the "rock solid way" you were looking for, but I've been working with the device policy manager along with the keyguard manager for some while and I came across similar problem that locknow() method would turn off screen and then turns back on devices with android 4.0 above.
I came across this solution while looking through the DDMS debug logs, and hopefully, testing on some devices. So far, it hasn't failed me so here a tip anyway.
Disable keyguard
call locknow()
reenable keyguard in a 300ms or so, with the above methods... ( I prefer the handler and it worked like a charm for me)

GPS Tracking App (strategy)

I am currently working on a GPS tracking App (only the distance, not storing each value or displaying in a MapView) for a car-drivers logbook.
Cause of a docked phone, I do not care about power consumption.
My implementation so far is an activity that calls a GPS-Helper class which is getting the long/lat.
The activity itself calculates the driven distance, displays it for the user and starts a notification bar that also displays the distance. To keep the activity active and not killed by the OS, I am using a PARTIAL WakeLock for the activity.
My problem is that this is not working correctly, cause my App seems to be killed by the OS inspite of the WakeLock. I think that it is killed, cause when I click on the notification bar item (after 15-30 min. for example) to see the driven distance in my running activity, the activity is shown as it is to start a new GPS-track instead of displaying the driven distance from the former started track.
The WAKELOCK Permission is correctly set in the Manifest.
My question now is to get know if this costruct could be working or is there a better way to do this?
Your problem may be with the Intent you are launching when you click on the notification. This intent is most likely thinking that you want to launch a brand new Activity rather than returning the old activity to the foreground.
This link may help you to do what you want:
How to bring Android existing activity to front via notification
You should use a service which calls startForground, which requires a notification. This notification will be your entry point back into the app. The service can run in the background and log coordinates without depending on the life cycle of your Activity.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent.getAction().equals(DRIVELOG_ACTION_STOPLOGGING)){ handleStopLoggingCommand(intent.getBooleanExtra(SAVE_LOG,false));
}
else if(intent.getAction().equals(DRIVELOG_ACTION_STARTLOGGING)){
handleStartLoggingCommand();
}
return START_STICKY;
}
private void handleStartLoggingCommand() {
startForeground(DriveLoggerNotification.notificationId,DriveLoggerNotification.createInDriveLogNotification(this,driveLogLiveData));
if(googleApiClient.isConnected()){
startMonitoringLocation();
}else {
googleApiClient.connect();
}
}
This code is from my GpsLoggingService

Categories

Resources