Подтвердить что ты не робот

Проверьте, была ли включена блокировка или нет.

Мне нужно проверить, была ли включена блокировка системы или нет.

Я использовал ниже код строки

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

Возвращает true, если я устанавливаю блокировку pattern, а false, если я устанавливаю пароль pin/password.

Мне нужно проверить, была ли блокировка включена или нет, либо она pattern/pin/password заблокирована в настройках.

Мой код работает только с pattern блокировкой не pin/password блокировки.

Итак, скажите, пожалуйста, как проверить все типы блокировок.

4b9b3361

Ответ 1

Итак, этот вопрос довольно старый, но, похоже, пока нет хорошего ответа. После некоторого исходного кода (из ссылка Рамакришны) исследования и самостоятельные эксперименты Я написал простой класс, который выполняет эту работу.

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

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

или если вы хотите только "Face Unlock" независимо от того, какой дополнительный метод

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

EDIT: так, я тестирую этот класс на 3 телефонах, и кажется, что не все телефоны правильно определяют способ разблокировки лица. На некоторых телефонах PASSWORD_QUALITY_BIOMETRIC_WEAK возвращается и PASSWORD_QUALITY_SOMETHING на чужих. Я думаю, что мы можем проверить, что файл, содержащий информацию для разблокировки лица, существует, а не пуст, подобно методам паролей/выводов и шаблонов. Но пока я не знаю, где именно находится этот файл.

EDIT2: Похоже, что я нашел проблему после исследования кода sordes android 4.3. Это потому, что параметры блокировки были перемещены в новое место (/data/system/locksettings.db), и, похоже, нет способа получить эти настройки из этой базы данных (rw-rw ---- permissions и "system" owner and group, поэтому только корень может выполнять эту работу).

Ответ 2

Будьте осторожны, этот метод также устарел! Спасибо 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;
}

Ответ 3

Начиная с 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
...
}

Ответ 4

@Peter Pint и esme_louise

Спасибо, ваше решение заставил меня идти. Чтобы узнать, включена ли блокировка экрана, я мог бы еще больше упростить ваш метод. Это возвращает false для прокрутки или правильной блокировки (PIN, PW, Face unlock и т.д.) И возвращает 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;
}

UPDATE: Я адаптировал код для android M, используя новый метод isDeviceSecure(). Однако это не позволяет больше различать "None" и "Swipe". Кроме того, метод уже начал сбой в 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

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

Ответ 8

@Peter Pint

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

... должен быть...

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

Но в остальном, прямо сейчас! Я подтвердил ваш ответ.

Ответ 9

Если вы говорите о блокировке экрана, вы можете попытаться настроить конкретный BroadcastReceiver и прослушать определенные Intents из системы.

Надеюсь, поможет. Извините, если я вас не поняла :)