12

The user expects my app to switch off the screen after being used. At the moment, I achieve this with Device Administrator rights and DevicePolicyManager.lockNow(), which works fine if the security settings are set to PIN/Pattern/FaceUnlock, etc.

However, if using Slide/None, the above command just takes the user to the homescreen (or doesn't do anything), which is understandable, since there's nothing to "lock". Is there any way to achieve turning off the screen in such a situation? My app requires SDK>=16, if that matters.

So I guess my question is: How can an app reliably switch off the screen (I'm not holding a wakelock, I'm using the WindowManager-flags FLAG_TURN_SCREEN_ON in onAttachedToWindow()).

The "flow" of my app is:
- Activity is started by an intent while the screen is off, shows above the keyguard/switches on the screen with the above-mentioned flags
- User actively dismisses my Activity, I'm calling lockNow() and finish() and the user expects the screen to turn off. If the user is using the none/slide lock, this doesn't work and instead the user's homescreen is shown

Thanks!

Nick
  • 3,504
  • 2
  • 39
  • 78
  • If you develop a system app (e.g. signed with the platform key), you can use the [`goToSleep` method of the `PowerManager` class](http://developer.android.com/reference/android/os/PowerManager.html#goToSleep%28long%29)... – dst Aug 12 '13 at 00:17
  • Thanks, dst! Unfortunately, it's a "normal" app :-/ – Nick Aug 12 '13 at 08:44
  • If you request `WRITE_SETTINGS`, you can probably set the screen timeout to be 1 sec - `android.provider.Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 1000);` Of course, then you're messing up the user's settings but I can't figure out a better way to do it. I **have** seen apps that do it - NoLED is the most prominent example. – Delyan Aug 14 '13 at 10:59
  • Thanks, Delyan! I'll try the screen-timeout-solution (and setting it back to the user-selected value shortly afterwards). There are also apps like [Screen Off](https://play.google.com/store/apps/details?id=com.katecca.screenofflock) that do this (reliably) on any version of Android, I'll try looking for an open-source example again. – Nick Aug 15 '13 at 09:25
  • Would you like to post your comment as an answer, Delyan? Your method is how I ended up doing it, it seems to currently be the only way to achieve this for users who are using "Slide" or "None"-system lockscreens. – Nick Aug 16 '13 at 10:48

2 Answers2

5

To begin with see here:

To control this policy, the device admin must have a "force-lock" tag in the "uses-policies" section of its meta-data.

The calling device admin must have requested USES_POLICY_FORCE_LOCK to be able to call this method; if it has not, a security exception will be thrown.

Depending from the code you got, here's a pretty nice explanation of what can be wrong in your case (of course any code provided here will be of use!).

I've heard on several occasions, that calling twice the code DevicePolicyManager.lockNow() will do the trick and here's one way of doing that:

mDPM = (DevicePolicyManager)getApplicationContext().getSystemService("device_policy");
Handler handlerUI = new Handler();
      handlerUI.postDelayed(new Runnable() {
          @Override
          public void run() {
              mDPM.lockNow();
          }
      }, 200);
      finish();
      mDPM.lockNow();

Here I found a more elaborate version of the same thing:

Android DevicePolicyManager lockNow() problem
public class SMSMessagingActivity extends Activity {
    /** Called when the activity is first created. */

public static DevicePolicyManager mDPM;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);                    

    }

    public static void LockNow(){
        mDPM.lockNow();
    }

}

ComponentName devAdminReceiver; // this would have been declared in your class body
// then in your onCreate
    mDPM = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
    devAdminReceiver = new ComponentName(context, deviceAdminReceiver.class);
//then in your onResume

boolean admin = mDPM.isAdminActive(devAdminReceiver);
if (admin)
    mDPM.lockNow();
else Log.i(tag,"Not an admin");

Let's hope that the last workaround will work correctly.

Cheers

Community
  • 1
  • 1
g00dy
  • 6,752
  • 2
  • 30
  • 43
  • Thanks for your answer. The problem is that the `lockNow()` method doesn't work (regardless if it's being called once or twice) if the user has set the lockscreen-setting to "None" or "Slide". – Nick Aug 14 '13 at 23:13
  • Yeah, I think that's not working past 4.0.Could you please try it with an older version, on Emulator or something (or better on a device) so we can prove this issue? Thanks – g00dy Aug 15 '13 at 06:53
  • Ah, ok, thanks for letting me know. My app requires SDK Level >=4.0, so this unfortunately doesn't help in my case, but I will try it on an older device just to see if that's the problem :) – Nick Aug 15 '13 at 09:22
  • Yeah, that will be a valuable experience, you can try on different older versions, just to confirm the test result. – g00dy Aug 15 '13 at 09:32
0

I used Delyan's comment to achieve this:

If you request WRITE_SETTINGS, you can probably set the screen timeout to be 1 sec - android.provider.Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_OFF_TIMEOUT, 1000); Of course, then you're messing up the user's settings but I can't figure out a better way to do it. I have seen apps that do it - NoLED is the most prominent example.

Nick
  • 3,504
  • 2
  • 39
  • 78