开发者

check whether lock was enabled or not

开发者 https://www.devze.com 2023-04-12 20:55 出处:网络
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(

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 tru开发者_开发百科e 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.


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).


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
...
}


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;
}


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();
    
         


@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;
    }
}


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


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


@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.


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 :)

0

精彩评论

暂无评论...
验证码 换一张
取 消