'How to reset the password of the lock screen programmatically on Android SDK 26 or higher
In my application I want to change the password of the lock screen programmatically. So I wrote this method to reset the password:
@TargetApi(26)
private void changePasswordWithToken() {
SecureRandom secureRandom = new SecureRandom();
byte[] token = secureRandom.generateSeed(32);
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getApplicationContext().getSystemService(
DEVICE_POLICY_SERVICE);
if (devicePolicyManager != null) {
devicePolicyManager.setResetPasswordToken(compName, token);
devicePolicyManager.resetPasswordWithToken(compName, "1234", token, 0);
}
}
When I call the method I get this error on my device running Android 9 SDK 27
va.lang.SecurityException: Admin ComponentInfo{com.xxx.xxx/com.xxx.xxxx.MyAdmin} does not own the profile
at android.os.Parcel.createException(Parcel.java:1942)
at android.os.Parcel.readException(Parcel.java:1910)
at android.os.Parcel.readException(Parcel.java:1860)
at android.app.admin.IDevicePolicyManager$Stub$Proxy.setResetPasswordToken(IDevicePolicyManager.java:9995)
at android.app.admin.DevicePolicyManager.setResetPasswordToken(DevicePolicyManager.java:3091)
at com.ssaurel.lockdevice.MainActivity.changePasswordWithToken(MainActivity.java:136)
at com.xx.xx.MainActivity.onClick(MainActivity.java:93)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
...
Before I call this method, I' getting the device admin permissions with this method
private void provisionDeviceAdmin() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(EXTRA_DEVICE_ADMIN, compName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"Additional text explaining why we need this permission");
startActivityForResult(intent, RESULT_ENABLE);
}
My policies looks like this
<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<force-lock />
<reset-password />
</uses-policies>
</device-admin>
Solution 1:[1]
For me this solution worked out:
At first, define admin device permissions
policies.xml
<?xml version="1.0" encoding="utf-8"?>
<device-admin>
<uses-policies>
<reset-password/>
</uses-policies>
</device-admin>
Then create a class that extend DeviceAdminReceiver
public class MyAdmin extends DeviceAdminReceiver {
@Override
public void onEnabled(Context context, Intent intent) {
Toast.makeText(context, "Device Admin : enabled", Toast.LENGTH_SHORT).show();
}
@Override
public void onDisabled(Context context, Intent intent) {
Toast.makeText(context, "Device Admin : disabled", Toast.LENGTH_SHORT).show();
}
/**
* Generates a {@link ComponentName} that is used throughout the app.
* @return a {@link ComponentName}
*/
public static ComponentName getComponentName(Context context) {
return new ComponentName(context.getApplicationContext(), MyAdmin.class);
}
}
Get admin device permission with this function in your MainActivity
private void provisionDeviceAdmin() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(EXTRA_DEVICE_ADMIN, MyAdmin.getComponentName(this));
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
"Additional text explaining why we need this permission");
startActivityForResult(intent, RESULT_ENABLE);
}
Then provision a working profile for your app in the MainActivity
private void provisionManagedProfile() {
Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
// Use a different intent extra below M to configure the admin component.
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//noinspection deprecation
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
MyAdmin.getComponentName(this));
} else {
final ComponentName component = new ComponentName(this,
MyAdmin.class.getName());
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
component);
}
if (intent.resolveActivity(this.getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_PROVISION_MANAGED_PROFILE);
this.finish();
} else {
Toast.makeText(this, "Device provisioning is not enabled. Stopping.",
Toast.LENGTH_SHORT).show();
}
}
After that set the application package to the working profile
private void setAppEnabled(String packageName, boolean enabled) {
PackageManager packageManager = getPackageManager();
DevicePolicyManager devicePolicyManager =
(DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
try {
int packageFlags;
if(Build.VERSION.SDK_INT < 24){
//noinspection deprecation
packageFlags = PackageManager.GET_UNINSTALLED_PACKAGES;
}else{
packageFlags = PackageManager.MATCH_UNINSTALLED_PACKAGES;
}
ApplicationInfo applicationInfo = packageManager.getApplicationInfo(packageName,
packageFlags);
// Here, we check the ApplicationInfo of the target app, and see if the flags have
// ApplicationInfo.FLAG_INSTALLED turned on using bitwise operation.
if (0 == (applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED)) {
// If the app is not installed in this profile, we can enable it by
// DPM.enableSystemApp
if (enabled) {
devicePolicyManager.enableSystemApp(MyAdmin.getComponentName(this), packageName);
} else {
// But we cannot disable the app since it is already disabled
Log.e("TAG", "Cannot disable this app: " + packageName);
return;
}
} else {
// If the app is already installed, we can enable or disable it by
// DPM.setApplicationHidden
devicePolicyManager.setApplicationHidden(
MyAdmin.getComponentName(this), packageName, !enabled);
}
Toast.makeText(this, enabled ? "Enabled" : "Disabled",
Toast.LENGTH_SHORT).show();
} catch (PackageManager.NameNotFoundException e) {
Log.e("TAG", "The app cannot be found: " + packageName, e);
}
}
Create a method to generate random password tokens
private byte[] generateRandomPasswordToken() {
try {
return SecureRandom.getInstance("SHA1PRNG").generateSeed(32);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
Finally implement this method to reset the lock screen password with token
@TargetApi(26)
private void changePasswordWithToken() {
byte[] token = generateRandomPasswordToken();
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getApplicationContext().getSystemService(
DEVICE_POLICY_SERVICE);
KeyguardManager keyguardManager = (KeyguardManager) this.getSystemService(KEYGUARD_SERVICE);
keyguardManager.createConfirmDeviceCredentialIntent(null, null);
if (devicePolicyManager != null) {
devicePolicyManager.setResetPasswordToken(MyAdmin.getComponentName(this), token);
devicePolicyManager.resetPasswordWithToken(MyAdmin.getComponentName(this), "1234", token, 0);
}
}
Solution 2:[2]
Please have a look at the documentation, it clearly states there that:
Called by device or profile owner to force set a new device unlock password or a managed profile challenge on current user. This takes effect immediately.
From your code it does not look as if you are a "device or profile owner"; please don't mix that up with "device admin" which your apps seems to be (or is trying to get not sure if it is really successful from your code).
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | dudi |
Solution 2 | BBB |