How to turn keyguard on in reliable way? - android

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)

Related

Android - Handler repeating task stops executing while the screen is on at Foreground Service

First of all, this is a long question but targeting only one topic, and I'm sorry I cannot share any code as it is a project of our company and is classified. We are using a foreground service that executes a task within 100 milliseconds only. Until I asked this question we used multiple approaches on executing a code in a short amount of time, follows:
A thread with "Thread.sleep" in it (not the best approach but it was our first try, went inconsistent),
A thread with "Object.wait" (same result as above),
Timer (also is inconsistent and stops executing after some time),
ScheduledThreadPoolExecutor which also has the problem of all above.
On my phone (HUAWEI P20 Lite), after trying these approaches, we finally decided to use a Handler with a HandlerThread as the work does not require to interact with UI thread. (not always but we are using a seperate handler for it.) In between every approach, this seems to be the most consistent one, however we don't know if it depends on the phone, manufacturer or anything, my phone stops executing the looping handler with postDelayed until I interact with the app UI in some way, for example: touching the notification, while the screen is on. Yes, I'm not talking about clicking the notification itself, but even touching, or like expanding the detail text starts the handler again. Which means, I think my phone is trying to save power with pausing the background execution.
Now, we only want to run this method while the screen is on, as we are already pausing the handler itself via "a screen on-off broadcast receiver" that registered in the foreground service by removing the callbacks of the runnable, but after screen goes on, broadcast is received but even if "Handler.post()" executes, it does not run the runnable inside, hence it never loops.
To give you a bit of context, this is what kind of logic we are following:
We open a foreground service with something similar to the below code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
getApplicationContext().startForegroundService(
new Intent(getApplicationContext(),
MyService.class));
}
else
{
getApplicationContext().startService(
new Intent(getApplicationContext(), MyService.class));
}
And then, inside the service we do something like the following:
public int onStartCommand()
{
// notification stuff
HandlerThread thread = new HandlerThread("myThread");
thread.start();
Handler handler = new Handler(thread.getLooper());
handler.post(new Runnable()
{
// do stuff
// this runnable stops executing after some time. This is where the problem lies.
handler.postDelayed(this, 100);
})
return START_STICKY;
}
The handler inside onStartCommand is unstable, sometimes it does not respect the delay, or sometimes it does not execute at all. Now, not respecting the delay is not the problem as we don't have to be that consistent as our calculations do not depend on the elapsed time or something, but if it stops executing (which in this case, it does), that's where the problem starts.
To handle this, we are going to use a brand new class that Android Jetpack offers, WorkManager, which is perfect for checking the status of handlers. To understand if the threads are active or not, we registered the last execution time of the code inside the handler and are going to access it via the worker class. Now, if the handlers are down, we would like to wake these handlers up. How can this be done? Because remember, this happens while the screen is on.
Edit: Here are some logs about how the thread execution goes.
//2018-12-19 11:35:15.048 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
//2018-12-19 11:35:15.154 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
2018-12-19 11:35:15.262 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
2018-12-19 11:35:45.262 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
//2018-12-19 11:35:45.365 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
//2018-12-19 11:35:45.468 17222-17952/com.example.something D/MyService: threadName: MainThread, postDelayedValue: true
Any suggestions? Any workarounds for this? Every help and comment is appreciated, thank you so much.
Found where the problem was, it is running smoothly everywhere else except on my device (and probably other devices which has EMUI on their system), which is apparently pretty strict about power management.
Here are the logs:
2018-12-19 16:45:52.943 12619-12822/com.example.something D/ThreadHelper: MainThread looping.
2018-12-19 16:45:52.986 1699-2028/? I/ash: com.example.something skips not important notification
2018-12-19 16:45:52.996 1699-2028/? I/ash: com.example.something { doze duration=40061 UptimeDuration=40061 } transition to: hibernation reason:
2018-12-19 16:45:52.996 1699-2028/? I/ash: perform hibernation actions: com.example.something
My device, by on it's own, decides that the process with a notification that is not important can be silently stopped, so I increased the importance of the notification with NotificationManager.IMPORTANCE_MAX. Now, it does not stop working at all.
If you experience something like this and want to assure that raising the notification won't be enough for you, then on HUAWEI devices there is a setting that can be opened with Settings --> Battery --> Launch. Disable your automatic app power management and make it manual, so the OS won't interfere with the process ever (hopefully).
Does it happen on pre-Oreo devices?
If you start a service with startForegroundService, you should immediately call setForeground on onStartCommand. Otherwise service is killed within a short amount of time.
Also, your handler reference is local to onStartCommand, that may be why it does not persist.

Android- Telephone app that keeps focus on outgoing & incoming phoneCall

Using this simple example to create a PhoneCall application that dials out a hard coded # and monitors phone state.
http://www.mkyong.com/android/how-to-make-a-phone-call-in-android/
Unfortunately, on making the phone call, we always switch to the actual built -in phone application.
I want to avoid this, or at the very least hide the dialer pad button. The user SHOULD NOT have the option to enter a phone#.
Does anyone know of a way to achieve this?
i.e. keep the actual built-in phone application in the background
(I would need to add buttons for speaker, and end call in the primary application)
OR
alternatively, hide just the dial pad button in the native, built-in phone application?
Here is a solution I came up with to hide the caller app shortly after the call is placed. I don't believe there is a way to make it totally transparent without re-writing the Android system. I believe this could be improved by detecting when the caller app is set up and dialing instead of the postDelayed() I'm using which could be unreliable.
EDIT: I tried making a receiver to listen for NEW_OUTGOING_CALL to restart the original Activity, but it doesn't really improve anything, the dialer app must be running for an arbitrary amount of time before it can start it's background service.
EDIT: I tried making a PhoneStateListener that listens for CALL_STATE_OFFHOOK and re starts the Activity there. This doesn't work either as it happens before the dialing app is fully ready to go into the background.
EDIT: You can look at this thread: Reflection to access advanced telephony features, but I believe Google has since locked down all methods of placing a call outside the standard app.
This solution will start the dialing, and then switch back to the original Activity after a couple of seconds.
In my manifest I have:
android:launchMode="singleInstance"
on my Activity so I don't get a new instance.
public class MainActivity extends Activity
{
....
public void clickMe(View view)
{
startService(new Intent(this, PhoneService.class));
}
}
public class PhoneService extends Service
{
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Intent call = new Intent(Intent.ACTION_CALL);
call.setData(Uri.parse("tel:XXXXXXXXX"));
call.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(call);
Handler h = new Handler();
h.postDelayed(new Runnable() {
#Override
public void run()
{
Intent act = new Intent(PhoneService.this, MainActivity.class);
act.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(act);
}
}, 4000);
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent arg0)
{
// TODO Auto-generated method stub
return null;
}
}
I believe it impossible to provide a cleaner solution, given the constraints of the SDK.
The functionality you are wanting isn't possible without some type of hack-ish work around. The Android system only allows the Phone app to control the underlying RIL and telephony stack and the Phone app UI responds to the dial URI by presenting this user with the dial screen where they must confirm (or alter) the number. This is a security provision to prevent unwanted apps from using the telephone device without the user knowing about it. Also, due to the way the Intent system works in Android, it is possible for other apps to handle calls using SIP or other VoIP functionality (i.e. Skype). In this case the user may have set a global preference to always use the other app and you have no control over how that app behaves with the dial Intent.

Clever way to wakeup Android background service on shake

I want my Android background to go into sleep mode - but then wake up when the user starts moving.
However, if I use the accelerometer in NORMAL mode (the lowest sample rate ~ 5Hz) I fear it would still consume too much power.
The best way to do it so far is on USER_PRESENT - screen on and unlocked.
Not even screen on(possibly with keyguard present) works, because, as many of you may know, there are plenty of bad apps out there that will hold a wakelock and start the screen from time to time.
I am contemplating having the user push the volume up/down buttons..
Is there any better solution to this?
don't know if you're still looking for a way to do this, but i discovered (by accident) that you can start a shakeListener, and your app will get the events, even when in the background.
(and by "by accident", i mean that i did not want my app playing the sound that it is supposed to play when the app is in the background, but even when had another app in the background, and then even put the phone to sleep, when i would walk with the phone in my pocket, it was enough shaking to cause the app to perform the operation in the background.)
/**
* load and set up the listener for shake detection
*/
private void loadShaker() {
mShaker = new ShakeListener(this);
mShaker.setOnShakeListener(new ShakeListener.OnShakeListener () {
public void onShake() {
if (!mActivityPaused)
performMyOperationCausedByShake();
}
});
}
you could probably thus set this up so that performMyOperationCausedByShake() performs an intent that causes your desired Activity to happen.
(it might be the case that this is not quite sensitive enough for what you're looking for …)

Keep activity on when screen is off

I got a service that start a new activity, while screen is off.
I want the activity to stay on paused mode, and not get to the stopped mode.
Is there a way to achieve this?
No. You don't have control over the Activity lifecycle. Any processes that you need to run while the screen is off must be executed in a Service. You must rebuild the application state whenever the screen is turned back on. Always assume the Activity can be wiped from memory at any time.
You can't do that. it will be killed anyway.
but you can use a Service to receive Broadcast of Intent.ACTION_SCREEN_ON and relaunch activity from Service.
to restart your Activity from service check here
There is no way to achieve this. Your app is tied to the Activity lifecycle, and has to break down/restore the Activities to work with the lifecycle.
You can't override the onDestroy() method, and each OS version handles how an application is "killed" differently.
The Android developer documentation makes reference to an application being in a “killable” state. While Android tries to keep the process of an application resident even after it has exited (i.e. after onDestroy), it does need to be able to kill these processes in low-resource situations to reclaim memory. The states in which an application is killable differ per OS version. On all versions of Android, applications that have returned from onStop or onDestroy are silently killable. On versions of Android prior to Honeycomb, applications that had returned from onPause were also killable. Being killable simple means that Android reserves the right to terminate your application’s process at any time without running even another instruction of your app’s code. In other words, if you have any state that must be recoverable (such as a player’s game progress, items, awards, etc) you must save those to persistent storage no later than the last callback before entering a killable state.
In addition, while applications can run native threads even when they are in a killable
state and even post-onDestroy, this is to be avoided, since the process kill will also kill those threads. This could cause all manner of corruption and shutdown issues.
Source
I do not exactly now what you mean with paused mode or stopped mode. If you mean that the cpu keep wake up take a look at this.
With partial_wake_look you can have a long running AsyncTask for example also when the screen is of. Dont't forget to release the wakelook.
Why do you need to do this? Maybe best solution is to run it as a service as suggested by #DeeV. However, depending of what you need to do, this could help:
Ask Android to notify you when screen is turned on (and off if required). So your activity can be resumed and started immediately and you can perform any action.
To do that:
Create a class which extends Application
Register it in your Manifest:
In public void onCreate() {..., add this:
IntentFilter ioff = new IntentFilter(Intent.ACTION_SCREEN_OFF);
IntentFilter ion = new IntentFilter(Intent.ACTION_SCREEN_ON);
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_SCREEN_OFF.equals(action)) {
//TODO
} else {
//TODO
}
}
};
context.registerReceiver(broadcastReceiver, ioff);
context.registerReceiver(broadcastReceiver, ion);
in public void onTerminate() {..., add this:
if (broadcastReceiver != null) {
context.unregisterReceiver(broadcastReceiver);
}
Lame hack would be to call onPause() method inside onStop() of activity

How to arrange long (time consuming) actions on Android?

For instance, we are in SomeActivity and the activity has a button that invokes moving files from one dir to another (let's call it job).
On BlackBerry I would:
push a non-cancellable popup (Dialog screen) saying "Please wait..."
start a thread that fulfills the job
on thread completion close the popup
This approach 99.99% can guarantee that we stay on the same screen after the task is over, user just sees the popup and waits for job completion. Device rotation or whatever does not break the desired workflow.
On Android things change. I know there's the AsyncTask that is probably provided to solve my case. There's even a good example of how it should be used. But since there's no guarantee of how long an Activity instance will live the AsyncTask should be cancelled on onSaveInstanceState (and restarted on onRestoreInstanceState). This means using AsyncTask there's no guarantee we are able to fully fulfill the job once started. In some cases as sending an http post request for creating a user I would not want to get in "user already exists for this login" trouble on reruning the AsyncTask. This is possible since the AsyncTask can be interrupted while the request is already sent (and the server actually is doing its job - creating a new user), but the AsyncTask is canceled before we got the response.
Is there any solution on Android to get the BB-like behaviour stated above?
But since there's no guarantee of how
long an Activity instance will live
the AsyncTask should be cancelled on
onSaveInstanceState (and restarted on
onRestoreInstanceState).
Or have it be managed by a Service.
If your Activity wants to stay on the screen, you can simply start a Thread like this:
final File fromFile = ...;
final File toFile = ...;
new Thread() {
#Override
public void run() {
// do something with fromFile, toFile
}
}.start();
That way the GUI-Thread is ready to do other thinks like displaying a
android.app.ProgressDialog
Also, consider making the Dialog uncancellable with
ProgressDialog.setCancelable(false);
That way the user can only leave via the HOME-Key, which you get notified of when
Activity.onPause()
is called. Futhermore you might want to look into Wakelocks, to stop the Screen from turning black and your application pushed in the background where it might be killed. You'd do this in the Thread:
PowerManager pm = (PowerManager) ivContext.getSystemService(Context.POWER_SERVICE);
Wakelock wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "MyApp");
wakeLock.acquire();
// ... copy stuff ...
wakeLock.release();
Of course you'd have to release the wakeLock, too, when the user leaves via the HOME-Key.
Finally if you want to call GUI-Elements from your background-thread, this will only work if the Thread is part of the GUI-Event-Loop, like the normal Thread is you are running in, when getting called with on...-Methods. To achieve this your background-thread will have to callback to the GUI-Thread via a Handler. Like this:
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
Log.v(TAG, "Got Message "+msg.what); // prints: Got Message 77
// ... do GUI actions ...
}
};
// ... in Thread ...
int lvInfo = 77;
mHandler.sendEmptyMessage(lvInfo);
You can even put objects in the message like so:
Message txtMsg = Message.obtain();
textMsg.obj = "Hello World";
mHandler.sendMessage(lvTextMsg);
In May 2010 Google issued a new IO session called Developing Android REST client applications which explains how to achieve exactly what I asked for.
It turned out the question is rather complicated, so there is no easy and quick solution. The solution requires deep knowledge of Android platform/API. This is the price caused by the flexibility of the app process/Activity lifecycles.
I feel some oddity on why this info was not presented from the very first version of Android. Looks like Google knew how to write 100% bugless apps and for some marketing reason did not share the approach. Just imagine how many buggy apps was written by May 2010.
Anyway I'm glad now I have smth we call best practice approach.

Categories

Resources