Android - как полностью отключить защиту клавиатуры

Я хочу контролировать включение / отключение клавиатуры на устройстве. Для этого я использую DevicePolicyManager и KeyguardLock API Android SDK.

Ниже моя реализация для управления этим:

public class DeviceLocker {

private static DeviceLocker instance;

public static synchronized DeviceLocker getInstance(Context context) {
    if(instance==null) {
        instance = new DeviceLocker(context);
    }
    return instance;
}

private Context context;
private KeyguardLock lock;

private DeviceLocker(Context context) {
    this.context = context;
}

public void lock() {
    lock(true);
}

public void lock(boolean lockNow) {
    getLock().reenableKeyguard();
    DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
    if(devicePolicyManager==null) {
        return;
    }
    LocalStorage storage = LocalStorage.from(context);

    boolean result = devicePolicyManager.resetPassword(storage.getPassword(),
            DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY);

    if(lockNow) {
        devicePolicyManager.lockNow();
    }
    storage.setDeviceLocked(true);
}

public void unlock() {
    DevicePolicyManager devicePolicyManager = getDevicePolicyManager();
    if(devicePolicyManager==null) {
        return;
    }
    devicePolicyManager.resetPassword("",0);
    getLock().disableKeyguard();
    LocalStorage.from(context).setDeviceLocked(false);
}

private KeyguardLock getLock() {
    if(lock==null){
        KeyguardManager kgManager = (KeyguardManager)context.getSystemService(Activity.KEYGUARD_SERVICE);
        lock = kgManager.newKeyguardLock(Context.KEYGUARD_SERVICE);
    }
    return lock;
}

private DevicePolicyManager getDevicePolicyManager() {
    DevicePolicyManager devicePolicyManager =
        (DevicePolicyManager)context.getSystemService(Context.DEVICE_POLICY_SERVICE);
    ComponentName deviceAdmin = new ComponentName(context, WatchGuardDeviceAdminReceiver.class);
    LocalStorage storage = LocalStorage.from(context);
    if(!devicePolicyManager.isAdminActive(deviceAdmin)) {
        return null;
    }
    if(!storage.isPasswordSet()) {
        UIUtils.showMessage(context, R.string.password_not_set);
        return null;
    }
    devicePolicyManager.setPasswordQuality(deviceAdmin,DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);

    return devicePolicyManager;
}

}

Он работает нормально в отношении блокировки экрана, но функция разблокировки работает с некоторыми проблемами: иногда она работает как я хочу (полностью удаляет любой тип экрана клавиатуры), но иногда показывает экран клавиатуры "Разблокировать с помощью слайда".

Вы знаете, в чем здесь проблема? Как сделать так, чтобы она работала стабильно (по крайней мере, во всех случаях показывать "Разблокировать для скольжения" или полностью убирать защиту клавиатуры)?

Заранее спасибо за помощь.

РЕДАКТИРОВАТЬ

Просто хочу отметить, что мое решение работает, но проблема в том, что оно работает нестабильно (иногда полностью удаляет защитную панель, а иногда показывает скользящую защитную панель). Кроме того, я использую его не только для отключения защиты клавиатуры при отображении некоторой активности, но и для общего управления блокировкой / разблокировкой устройства, поэтому я использую этот код в Сервисе, поэтому не могу вызвать getWindow().addFlags(..) потому что у меня нет окна, чтобы подать заявку.

Просто интересно, может кто-нибудь имел дело с этим нестабильным поведением.

5 ответов

Вам нужно добавить этот код:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED|WindowManager.LayoutParams.FLAG_FULLSCREEN|
                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.lockscreen);

        startService(new Intent(this,LockService.class).setAction(Intent.ACTION_SCREEN_OFF));
    }

Создать LockService с:

@Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {

        if(intent == null || intent.getAction() == null)
            return START_NOT_STICKY;

        String action = intent.getAction();

        if(action.equals(ACTION_SCREEN_OFF))
        {
           KeyguardManager.KeyguardLock k1;
           KeyguardManager km =(KeyguardManager)getSystemService(KEYGUARD_SERVICE);
           k1= km.newKeyguardLock("IN");
           k1.disableKeyguard();  
        }

        return START_NOT_STICKY;
    }

На самом деле я не знаю почему, но k1.disableKeyguard(); работает только в Сервисе.

AFAIK, это не всегда возможно, иначе это было бы серьезным нарушением безопасности.

На телефоне без рутирования самое большее, что вы можете сделать - это отменить небезопасную защиту клавиатуры или показать свое приложение над защищенной защитой клавиатуры.

Вот комбо, чтобы сделать это:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);

На рутированном телефоне вы можете попытаться удалить защищенную защиту клавиатуры (хотя вам может потребоваться перезагрузить устройство, прежде чем оно действительно исчезнет).

Вот комбо для этого (я не пробовал сам, но я уверен, что некоторые приложения "разблокировать телефон" в Play Store используют этот трюк)

Runtime.getRuntime().exec("sudo rm /data/system/gesture.key");

Я рекомендую сначала попробовать это через adb. Кроме того, вот ветка XDA с дополнительной информацией по этому вопросу: http://forum.xda-developers.com/showthread.php?t=1800799

KeyguardManager keyguardManager = (KeyguardManager)getSystemService(Activity.KEYGUARD_SERVICE);
KeyguardLock lock = keyguardManager.newKeyguardLock(KEYGUARD_SERVICE);
lock.disableKeyguard();

<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>

or 

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

Я бы порекомендовал использовать флаги окна dismiss_keyguard или show_when_locked, если у вас есть окно, которое должно открываться поверх экрана блокировки прямо при пробуждении.

http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html

как вы используете это следующим образом (вызывается в onCreate перед настройкой макета)

getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);

для Android 27+ вы можете сделать это:

       private fun dismissKeyguard() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
            setTurnScreenOn(true)
            setShowWhenLocked(true)
            (getSystemService(Context.KEYGUARD_SERVICE) as? KeyguardManager?)?.requestDismissKeyguard(
                this, object : KeyguardManager.KeyguardDismissCallback() {
                 //log if success or failure
                }
            )
        } else {
            window?.addFlags(
                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                        or WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
            )
        }
    }

Я добавил проверку допустимости значений NULL в этом вызове(getSystemService(Context.KEYGUARD_SERVICE) as? KeyguardManager?)потому что по какой-то причине некоторые случайные устройства не всегда имеют этот метод, и чтобы избежать исключений, я просто добавил обнуляемость

Другие вопросы по тегам