kowalski
kowalski

Reputation: 81

Android - how to completely disable keyguard

I want to control enabling/disabling keyguard on the device. To do that I'm using DevicePolicyManager and KeyguardLock API of Android SDK.

Below is my implementation to manage this:

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

}

It works ok regarding the lock of the screen, but unlock functionality works with some issues: sometimes it works as I want(completely removes any type of keyguard screen), but sometimes it shows a "Unlock with slide" keyguard screen.

Do you know what is the problem here? How to make it work stable (at least in all cases either show "Unlock to slide" or completely remove keyguard)?

Thanks in advance for your help.

EDIT

Just want to point out that my solution works but the problem is that it works unstable (sometimes removes keyguard completely and sometimes shows "slide" keyguard). And also I use it not just to disable the keyguard while showing some activity but to control lock/unlock of a device in common, so I use this code in Service, therefore I can't call getWindow().addFlags(..) cause I don't have the Window to apply.

Just wondering maybe anyone dealt with this unstable behavior.

Upvotes: 8

Views: 35754

Answers (5)

Ivan Bartsov
Ivan Bartsov

Reputation: 21066

Note: at the time of writing this, I probably didn't realise the question was about Device Management specifically, my answer would be fit for a regular app but it's not appropriate for device policy controller scenarios, so I'm crossing out the invalid statement below but leaving the answer in place for the sake of whatever value it has to offer. Credits for noticing this go to @Keilaron

AFAIK it's not universally possible, otherwise, this would be a major security breach.

On a non-rooted phone, the most you can do is dismiss a non-secure keyguard or show your app above the secure keyguard.

Here's a combo to do this:

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

On a rooted phone, you can attempt to remove the secure keyguard (although you may have to reboot the device before it actually goes away).

Here's a combo for that (haven't tried it myself, but I'm pretty sure several "unlock your phone" apps in Play Store use this trick)

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

I recommend you try this one through adb first. Also, here's an XDA thread with some more info on this: http://forum.xda-developers.com/showthread.php?t=1800799

Upvotes: 5

Javier
Javier

Reputation: 1685

for Android 27+ you can do this:

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

I added nullability check in this call (getSystemService(Context.KEYGUARD_SERVICE) as? KeyguardManager?) because for some reason some random devices does not have this method always and to avoid exceptions I just added nullability

Upvotes: 0

dooplaye
dooplaye

Reputation: 1029

You need to add this code:

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

Create LockService with:

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

Actually, I don't know why, but k1.disableKeyguard(); works only in Service.

Upvotes: 5

Hassaan Rabbani
Hassaan Rabbani

Reputation: 2465

i would recommend using the window flags dismiss_keyguard or show_when_locked if you have a window that needs to come over the top of the lockscreen right at wakeup.

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

how you use this is as follows (called in onCreate before setting layout)

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

Upvotes: 0

Swapnil
Swapnil

Reputation: 654

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

Upvotes: 1

Related Questions