35

I have to check whether system lock was enabled or not in settings.

I used below line code

boolean b = android.provider.Settings.System.getInt(
                        getContentResolver(),Settings.System.LOCK_PATTERN_ENABLED, 0)==1;

It returns true if i set pattern lock and it false for if i set pin/password password.

I need to check whether lock was enabled or not either it is pattern/pin/password lock in settings.

My code is only works to pattern lock not to pin/password lock.

So please tell me how to check for all type of locks.

Ramakrishna
  • 4,066
  • 16
  • 48
  • 72
  • In case of someone didn't find another answer: http://stackoverflow.com/questions/21748979/android-4-3-how-can-i-check-if-user-has-lock-enabled – Than Jun 10 '14 at 10:57
  • For API 16+ and PIN / PASS / PATTERN checking check here http://stackoverflow.com/a/27801128/236743 – Dori Jul 03 '15 at 16:10

9 Answers9

21

Starting with Android 6.0 Marshmallow (SDK 23), there is a new method to accomplish this task. Check this

http://developer.android.com/reference/android/app/KeyguardManager.html#isDeviceSecure()

Usage:

public static boolean isDeviceSecure(Context context)
{        
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
    {
        KeyguardManager manager = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
        return manager.isDeviceSecure();
    }
// reflection code from the other answers here
...
}
Gluttton
  • 5,739
  • 3
  • 31
  • 58
AndyB
  • 556
  • 1
  • 9
  • 25
20

So this question is pretty old but it seems there is no some good answer yet. After some source code (from Ramakrishna's link) research and self experiments I'm wrote simple class that do the job.

public class LockType
{
    private final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";

    /**
     * This constant means that android using some unlock method not described here.
     * Possible new methods would be added in the future releases.
     */
    public final static int SOMETHING_ELSE = 0;

    /**
     * Android using "None" or "Slide" unlock method. It seems there is no way to determine which method exactly used.
     * In both cases you'll get "PASSWORD_QUALITY_SOMETHING" and "LOCK_PATTERN_ENABLED" == 0.
     */
    public final static int NONE_OR_SLIDER = 1;

    /**
     * Android using "Face Unlock" with "Pattern" as additional unlock method. Android don't allow you to select
     * "Face Unlock" without additional unlock method.
     */
    public final static int FACE_WITH_PATTERN = 3;

    /**
     * Android using "Face Unlock" with "PIN" as additional unlock method. Android don't allow you to select
     * "Face Unlock" without additional unlock method.
     */
    public final static int FACE_WITH_PIN = 4;

    /**
     * Android using "Face Unlock" with some additional unlock method not described here.
     * Possible new methods would be added in the future releases. Values from 5 to 8 reserved for this situation.
     */
    public final static int FACE_WITH_SOMETHING_ELSE = 9;

    /**
     * Android using "Pattern" unlock method.
     */
    public final static int PATTERN = 10;

    /**
     * Android using "PIN" unlock method.
     */
    public final static int PIN = 11;

    /**
     * Android using "Password" unlock method with password containing only letters.
     */
    public final static int PASSWORD_ALPHABETIC = 12;

    /**
     * Android using "Password" unlock method with password containing both letters and numbers.
     */
    public final static int PASSWORD_ALPHANUMERIC = 13;

    /**
     * Returns current unlock method as integer value. You can see all possible values above
     * @param contentResolver we need to pass ContentResolver to Settings.Secure.getLong(...) and
     *                        Settings.Secure.getInt(...)
     * @return current unlock method as integer value
     */
    public static int getCurrent(ContentResolver contentResolver)
    {
        long mode = android.provider.Settings.Secure.getLong(contentResolver, PASSWORD_TYPE_KEY,
                DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
        if (mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
        {
            if (android.provider.Settings.Secure.getInt(contentResolver, Settings.Secure.LOCK_PATTERN_ENABLED, 0) == 1)
            {
                return LockType.PATTERN;
            }
            else return LockType.NONE_OR_SLIDER;
        }
        else if (mode == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK)
        {
            String dataDirPath = Environment.getDataDirectory().getAbsolutePath();
            if (nonEmptyFileExists(dataDirPath + "/system/gesture.key"))
            {
                return LockType.FACE_WITH_PATTERN;
            }
            else if (nonEmptyFileExists(dataDirPath + "/system/password.key"))
            {
                return LockType.FACE_WITH_PIN;
            }
            else return FACE_WITH_SOMETHING_ELSE;
        }
        else if (mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC)
        {
            return LockType.PASSWORD_ALPHANUMERIC;
        }
        else if (mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC)
        {
            return LockType.PASSWORD_ALPHABETIC;
        }
        else if (mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
        {
            return LockType.PIN;
        }
        else return LockType.SOMETHING_ELSE;
    }

    private static boolean nonEmptyFileExists(String filename)
    {
        File file = new File(filename);
        return file.exists() && file.length() > 0;
    }
}

Now you just need to do

int lockType = LockType.getCurrent(getContentResolver());

from your Activity class. If you want to check some set of lock types then just use switch statement

switch (lockType) 
{
    case LockType.FACE_WITH_PATTERN:
    case LockType.FACE_WITH_PIN:
    case LockType.PATTERN:
        /* do something */
        break;
}

or if you want only "Face Unlock" no matter with which additional method

if (lockType >= LockType.FACE_WITH_PATTERN && lockType <= LockType.FACE_WITH_SOMETHING_ELSE)
{
    /* do something */
}

EDIT: so, I'm test this class on 3 phones and it seems not all phones correctly detect face unlock method. On some phones PASSWORD_QUALITY_BIOMETRIC_WEAK returns and PASSWORD_QUALITY_SOMETHING on anothers. I think we can check some file that contains info for face unlock is exists and not empty, similar to password/pin and pattern methods. But for now I don't know where exactly this file is.

EDIT2: Looks like I found the problem after android 4.3 sorce code research. That's because lock settings was moved to new location (/data/system/locksettings.db) and it seems there is no way to get those setting from this database (rw-rw---- permissions and "system" owner and group so only root can do the job).

Community
  • 1
  • 1
s.maks
  • 2,583
  • 1
  • 23
  • 27
  • 2
    It's been reported to me that this method doesn't work with certain Samsung and Sony devices. At least PIN lock returns NONE_OR_SLIDER. Has anyone else had this issue? – Janne Oksanen Apr 08 '14 at 11:22
  • 1
    Doesn't work on HTC ONE S either, both pin and password returns NONE_OR_SLIDER – Than Jun 10 '14 at 10:43
  • 1
    Thank you, s.maks & Peter Pint, good answers in the thread. The only thing i'm missing here is new protection by fingerprint. Is there a way to detect it too? – Igor K Jan 13 '15 at 11:33
  • 1
    I can confirm that the code above does not return a reliable result on Samsung phones. – AndyB Jul 31 '15 at 12:01
  • Yeah, this code is actually dirty as hell, because, as usual, there is no way to do the job with official Android API. Also I think it's pretty much outdated now so I suggest everybody reading this comment to try another aproaches. – s.maks Aug 06 '15 at 13:58
  • Can we somehow differentiate if the user has NONE vs SLIDER ? – user2436032 Aug 20 '15 at 13:20
14

Be careful, this method seems to be outdated too! Thank you Dantalian for the hint!

LockPatternUtils is a private class. But you can read the lock mode with some reflection: (works with Nexus5, Android 4.4.4)

private boolean isDeviceSecured()
{
    String LOCKSCREEN_UTILS = "com.android.internal.widget.LockPatternUtils";
    try
    { 
        Class<?> lockUtilsClass = Class.forName(LOCKSCREEN_UTILS);
        // "this" is a Context, in my case an Activity
        Object lockUtils = lockUtilsClass.getConstructor(Context.class).newInstance(this);

        Method method = lockUtilsClass.getMethod("getActivePasswordQuality");

        int lockProtectionLevel = (Integer)method.invoke(lockUtils); // Thank you esme_louise for the cast hint

        if(lockProtectionLevel >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
        {
            return true;
        }
    }
    catch (Exception e)
    {
        Log.e("reflectInternalUtils", "ex:"+e);
    }

    return false;
}
Peter Pint
  • 141
  • 1
  • 4
11

For all version

KeyguardManager km = (KeyguardManager)getApplicationContext().getSystemService(Context.KEYGUARD_SERVICE);
if(km.isKeyguardSecure())
    Toast.makeText(getApplicationContext(), "locked", Toast.LENGTH_LONG).show();
else
    Toast.makeText(getApplicationContext(), "Unlocked", Toast.LENGTH_LONG).show();
    
         
Sanjayrajsinh
  • 15,014
  • 7
  • 73
  • 78
Yazjaz Jaz
  • 121
  • 1
  • 2
7

@Peter Pint and esme_louise

Thanks, your solution got me going. To find out whether the screen lock is enabled or not I could simplify your method even further. This returns false for swipe or proper lock (PIN, PW, Face unlock, etc.) and returns false for the option 'None'. For the distinction between swipe and one of the proper lock methods I use KeyguardManager.isKeyguardSecure()

It should work with API level 14+:

private boolean isLockScreenDisabled(Context context)
{
    String LOCKSCREEN_UTILS = "com.android.internal.widget.LockPatternUtils";

    try
    { 
        Class<?> lockUtilsClass = Class.forName(LOCKSCREEN_UTILS);
        // "this" is a Context, in my case an Activity
        Object lockUtils = lockUtilsClass.getConstructor(Context.class).newInstance(context);

        Method method = lockUtilsClass.getMethod("isLockScreenDisabled");

        boolean isDisabled = Boolean.valueOf(String.valueOf(method.invoke(lockUtils)));

        return isDisabled;
    }
    catch (Exception e)
    {
        Log.e("reflectInternalUtils", "ex:"+e);
    }

    return false;
}

UPDATE: I have adapted the code to android M using the new method isDeviceSecure(). However, this does not allow to differentiate between 'None' and 'Swipe' any more. Additionally, the method already started to fail at 5.x (I think 5.1.1) with a SecurityException. This required an extra hack in the catch block.

For my purpose of detecting whether the user is absent and USER_PRESTENT will be broadcast when the device is activated/unlocked isDeviceSecure() is good enough and I'm glad to get rid of the brittle reflection stuff for future releases.

private boolean isLockScreenDisabled(Context context)
{
    // Starting with android 6.0 calling isLockScreenDisabled fails altogether because the
    // signature has changed. There is a new method isDeviceSecure which, however, does
    // not allow the differentiation between lock screen 'None' and 'Swipe.
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){

        KeyguardManager keyguardMgr = (KeyguardManager) context
                .getSystemService(Context.KEYGUARD_SERVICE);

        // But luckily there is no 'Automatically lock x minutes after sleep' option when 
        // 'Swipe' is set which means that as soon as the screen is off, switching back on 
        // requires a swipe which results in a USER_PRESENT broadcast. 
        return !keyguardMgr.isDeviceSecure();
    }

    String LOCKSCREEN_UTILS = "com.android.internal.widget.LockPatternUtils";

    try 
    {
        Class<?> lockUtilsClass = Class.forName(LOCKSCREEN_UTILS);

        Object lockUtils = lockUtilsClass.getConstructor(Context.class).newInstance(context);

        Method method = lockUtilsClass.getMethod("isLockScreenDisabled");

        // Starting with android 5.x this fails with InvocationTargetException 
        // (caused by SecurityException - MANAGE_USERS permission is required because
        //  internally some additional logic was added to return false if one can switch between several users)
        // if (Screen Lock is None) { 
        //   ... exception caused by getting all users (if user count)
        // } else {
        //   return false;
        // }
        // -> therefore if no exception is thrown, we know the screen lock setting is
        //    set to Swipe, Pattern, PIN/PW or something else other than 'None'

        boolean isDisabled;
        try {

            isDisabled = Boolean.valueOf(String.valueOf(method.invoke(lockUtils)));
        }
        catch (InvocationTargetException ex) {
            Log.w(TAG, "Expected exception with screen lock type equals 'None': " + ex);
            isDisabled = true;
        }
        return isDisabled;
    }
    catch (Exception e)
    {
        Log.e(TAG, "Error detecting whether screen lock is disabled: " + e);

        e.printStackTrace();
    }

    return false;
}

And this is the method using it: It determines whether the user is absent in a way that the next time the screen is turned on (if no screen lock is set up) or the device is unlocked (including swipe) a USER_PRESENT_ACTION is broadcast.

public boolean isUserAbsent(Context context) {

    KeyguardManager kgMgr = (KeyguardManager) context
            .getSystemService(Context.KEYGUARD_SERVICE);

    boolean isDeviceLocked = kgMgr.inKeyguardRestrictedInputMode();

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
        // there was no 'None' option for screen lock in the olden days
        return isDeviceLocked;
    }

    PowerManager powerManager = (PowerManager) context
            .getSystemService(Context.POWER_SERVICE);

    if (isLockScreenDisabled(context)) {

        // Lock Type 'None' (USER_PRESENT is broadcast when screen comes on)

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
            // android 3.0 - 4.1: we have a problem with 'None' because
            // user_present is never broadcast!
            UserLog.log(TAG, context,
                    "No screen lock on android 3.0 - 4.1: User-presence will not be detected! Please switch to 'Swipe'");
        }

        return !powerManager.isInteractive();
    } else {
        // Lock Type 'Swipe' or proper lock  (USER_PRESENT is broadcast when device is unlocked)
        return isDeviceLocked;
    }
}
Mani
  • 71
  • 1
  • 3
  • This worked like a charm up to Lollipop 5.1.x. Now in Marshmallow 6.0 this is no longer working. Throws "methodnotfoundexception". Does anybody have an idea? – AndyB Oct 07 '15 at 07:58
  • The reason is this: https://github.com/android/platform_frameworks_base/commit/8150d2a2a12b38598fd55d8ae3c3b5662ec3520f They changed the method signature, now you must explicitly set an userId, but I guess there is no easy way to retrieve it. Does anybody know a new API to check if the device is using a Lock Screen protection (pattern, pin, password...)? – AndyB Oct 07 '15 at 09:54
  • 1
    There is a new method in Marshmallow http://developer.android.com/reference/android/app/KeyguardManager.html#isDeviceSecure() – AndyB Oct 07 '15 at 15:18
5

The above is the hard way. Use KeyguardManager.isKeyguardSecure()

Jim
  • 69
  • 1
  • 1
  • Why the -1? This is a more precise answer to the question. – Jim Sep 29 '14 at 00:03
  • 2
    This will be true if a Pin or Password is set, not a Pattern etc though. See http://blog.learningtree.com/of-pins-and-passwords-and-jelly-bean/ – Dori Jan 06 '15 at 13:51
  • @Dori, from the docs: """public boolean isKeyguardSecure (): Return whether the keyguard is secured by a PIN, pattern or password or a SIM card is currently locked.""" So it does seem to return true when a Pattern is set. – Divisible by Zero Dec 28 '15 at 09:58
  • @CiskeBoekelo `isKeyguardSecure()` changed in M – Dori Jan 04 '16 at 14:23
  • KeyguardManager mgr = ( KeyguardManager ) context.getSystemService( KEYGUARD_SERVICE ); mgr.isKeyguardSecure(); This worked for android m devices – user2582324 May 17 '16 at 07:44
2

This can also be achieved using Device Admin Policies http://developer.android.com/guide/topics/admin/device-admin.html

Dori
  • 18,283
  • 17
  • 74
  • 116
1

@Peter Pint

int lockProtectionLevel = (int)method.invoke(lockUtils);

...should instead be...

int lockProtectionLevel = Integer.valueOf(String.valueOf(method.invoke(lockUtils)));

But otherwise, right on! I've upvoted your answer.

esme_louise
  • 540
  • 2
  • 9
  • 28
0

If you talk about the screen lock you may try to setup specific BroadcastReceiver and listen to specific Intents from the system.

Hope it helps. Sorry if I didn't understand you :)

Marcel Bro
  • 4,907
  • 4
  • 43
  • 70
ihrupin
  • 6,932
  • 2
  • 31
  • 47
  • 1
    already i registered a receiver that extends DeviceAdminReceiver. Every thing works fine. Now i am getting the password was enabled or not. So i used the above code. It just works to pattern password not to pin/password in settings. – Ramakrishna Oct 15 '11 at 09:50