检查锁是否已启用

时间:2011-10-14 14:10:59

标签: android

我必须检查设置中是否启用了系统锁定。

我使用下面的行代码

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

如果我设置pattern锁定则返回true,如果我设置pin/password密码则返回false。

我需要检查是否启用了锁定,pattern/pin/password锁定设置。

我的代码仅适用于pattern锁定pin/password锁定。

所以请告诉我如何检查所有类型的锁。

9 个答案:

答案 0 :(得分:19)

所以这个问题已经很老了,但似乎还没有一些好的答案。在一些源代码(来自Ramakrishna's link)研究和自我实验之后,我写了一个简单的类来完成这项工作。

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

现在你只需要做

int lockType = LockType.getCurrent(getContentResolver());
来自Activity课程的

。 如果要检查一些锁定类型,请使用switch statement

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

或者如果您只想要“面部解锁”,无论使用哪种方法

if (lockType >= LockType.FACE_WITH_PATTERN && lockType <= LockType.FACE_WITH_SOMETHING_ELSE)
{
    /* do something */
}
编辑:所以,我在3部手机上测试这个课程,似乎并非所有手机都能正确检测到面部解锁方法。在某些手机上PASSWORD_QUALITY_BIOMETRIC_WEAK会在其他手机上返回PASSWORD_QUALITY_SOMETHING。我想我们可以检查一些包含面部解锁信息的文件是否存在而不是空的,类似于密码/引脚和模式方法。但是现在我不知道这个文件到底在哪里。

EDIT2:看起来我在android 4.3 sorce代码研究后发现了问题。那是因为锁定设置被移动到新位置(/data/system/locksettings.db),似乎没有办法从这个数据库中获取这些设置(rw-rw ----权限和“系统”所有者和组所以只有root可以完成这项工作)。

答案 1 :(得分:13)

小心,这种方法似乎也已经过时了!感谢Dantalian的暗示!

LockPatternUtils是一个私有类。 但你可以通过一些反思阅读锁定模式:(适用于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;
}

答案 2 :(得分:11)

从Android 6.0 Marshmallow(SDK 23)开始,有一种新方法可以完成此任务。检查一下

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

用法:

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

答案 3 :(得分:7)

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

答案 4 :(得分:6)

@Peter Pint和esme_louise

谢谢,你的解决方案让我走了。要确定是否启用了屏幕锁定,我可以进一步简化您的方法。滑动或正确锁定(PIN,PW,面部解锁等)返回false,对“选项”选项返回false。为了区分滑动和正确的锁定方法之一,我使用了KeyguardManager.isKeyguardSecure()

它应该适用于API级别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;
}

更新: 我已经使用新方法isDeviceSecure()将代码改编为android M.但是,这不允许区分“无”和“滑动”。 此外,该方法已经开始在5.x(我认为5.1.1)失败,带有SecurityException。这需要在catch块中额外进行攻击。

我的目的是检测用户是否缺席,并且当设备被激活/解锁时将播放USER_PRESTENT isDeviceSecure()已经足够好了,我很高兴为将来的版本删除脆弱的反射内容。

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

这是使用它的方法:它确定用户是否以下次打开屏幕的方式缺席(如果没有设置屏幕锁定)或设备未锁定(包括滑动)USER_PRESENT_ACTION播出。

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

答案 5 :(得分:5)

以上是艰难的方式。使用KeyguardManager.isKeyguardSecure()

答案 6 :(得分:2)

这也可以使用设备管理员政策http://developer.android.com/guide/topics/admin/device-admin.html

来实现

答案 7 :(得分:1)

@Peter Pint

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

......应该是......

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

但除此之外,马上!我已经对你的回答进行了投票。

答案 8 :(得分:0)

如果您谈论屏幕锁定,您可以尝试设置特定的BroadcastReceiver并从系统中侦听特定的Intent。

希望它有所帮助。对不起,如果我不理解你:)