Android Question Screen lock problem

Elyza

Member
Hello everyone, I followed these steps:

1- Create a project using the Administrator library.
2- Activate device manager.

I can lock the device with manager.LockScreen, but if I enter this command:

B4X:
manager.ResetPassword("0000")

I get this error:

java.lang.SecurityException: Device admin can no longer call resetPassword()

The complete error:

B4X:
main_btndisable_longclick (java line: 369)
java.lang.SecurityException: Device admin can no longer call resetPassword()
    at android.os.Parcel.createExceptionOrNull(Parcel.java:3011)
    at android.os.Parcel.createException(Parcel.java:2995)
    at android.os.Parcel.readException(Parcel.java:2978)
    at android.os.Parcel.readException(Parcel.java:2920)
    at android.app.admin.IDevicePolicyManager$Stub$Proxy.resetPassword(IDevicePolicyManager.java:6712)
    at android.app.admin.DevicePolicyManager.resetPassword(DevicePolicyManager.java:5728)
    at anywheresoftware.b4a.objects.AdminManager.ResetPassword(AdminManager.java:73)
    at mx.vmagic.ghost.main._btndisable_longclick(main.java:369)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:221)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:205)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:201)
    at anywheresoftware.b4a.objects.ViewWrapper$2.onLongClick(ViewWrapper.java:90)
    at android.view.View.performLongClickInternal(View.java:7661)
    at android.view.View.performLongClick(View.java:7619)
    at android.widget.TextView.performLongClick(TextView.java:13010)
    at android.view.View.performLongClick(View.java:7637)
    at android.view.View$CheckForLongPress.run(View.java:29774)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:211)
    at android.os.Looper.loop(Looper.java:300)
    at android.app.ActivityThread.main(ActivityThread.java:8445)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:560)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:954)
Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.devicepolicy.DevicePolicyManagerService.resetPassword(DevicePolicyManagerService.java:5014)
    at android.app.admin.IDevicePolicyManager$Stub.onTransact(IDevicePolicyManager.java:3178)
    at android.os.Binder.execTransactInternal(Binder.java:1285)
    at android.os.Binder.execTransact(Binder.java:1249)
java.lang.SecurityException: Device admin can no longer call resetPassword()
** Activity (main) Pause, UserClosed = false **

I read that there is a method that should be used now (resetPasswordWithToken()) but I don't know how to use it. I found this example:

B4X:
private void changePassword() {
    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), "9876", token, 0);
    }
}

private byte[] generateRandomPasswordToken() {
    try {
        return SecureRandom.getInstance("SHA1PRNG").generateSeed(32);
    } catch (NoSuchAlgorithmException e) {
        return null;
    }
}

Could someone help me with something?

Thank you very much and greetings.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You can call the two methods with:
B4X:
Dim ComponentName As Object = admin.As(JavaObject).GetField("rec")
Dim DevicePolicyManager As JavaObject = admin.As(JavaObject).GetField("dm")
Dim sr As SecureRandom 'Encryption library
Dim token(32) As Byte
sr.GetRandomBytes(token)

DevicePolicyManager.RunMethod("setResetPasswordToken", Array(ComponentName, token))
DevicePolicyManager.RunMethod("resetPasswordWithToken", Array(ComponentName, "9876", token, 0)

Make sure to go over the documentation and understand how these methods should be used.
 
Last edited:
Upvote 0

Elyza

Member
You can call the two methods with:
B4X:
Dim ComponentName As Object = admin.As(JavaObject).GetField("rec")
Dim DevicePolicyManager As JavaObject = admin.As(JavaObject).GetField("dm")
Dim sr As SecureRandom 'Encryption library
Dim token(32) As Byte
sr.GetRandomBytes(token)

DevicePolicyManager.RunMethod("setResetPasswordToken", Array(ComponentName, token))
DevicePolicyManager.RunMethod("resetPasswordWithToken", Array(ComponentName, "9876, token, 0)

Make sure to go over the documentation and understand how these methods should be used.

First, thank you very much for your answer Erel, but I still can't get this to work, when trying to adapt the code that you kindly shared with me, I get this error:

B4X:
java.lang.RuntimeException: Method: resetPasswordWithToken not matched.

The code of my project is this:

B4X:
Sub Process_Globals
    Public manager As AdminManager
End Sub

Sub Globals
    Dim rp As RuntimePermissions
    
    Dim ComponentName As Object = manager.As(JavaObject).GetField("rec")
    Dim DevicePolicyManager As JavaObject = manager.As(JavaObject).GetField("dm")
    Dim sr As SecureRandom 'Encryption library
    Dim token(32) As Byte
End Sub
Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
    
    rp.CheckAndRequest(rp.PERMISSION_RECEIVE_SMS)
    rp.CheckAndRequest(rp.PERMISSION_READ_SMS)
End Sub

Sub Activity_PermissionResult (Permission As String, Result As Boolean)
    If Permission = rp.PERMISSION_RECEIVE_SMS Then
        If Result Then
            Log("Permiso")
        End If
    Else If Permission = rp.PERMISSION_READ_SMS Then
        If Result Then
            Log("Permiso 2")
        End If
    End If
End Sub

Sub Activity_Resume
'    End If
End Sub

Sub btnEnable_Click
    If manager.Enabled = False Then
        manager.Enable("Favor de habilitar el administrador para obtener acceso a las funciones de seguridad.")
    End If
End Sub

Sub btnDisable_Click
    manager.Disable
End Sub

Sub btnLock_Click
    If manager.Enabled Then manager.LockScreen
End Sub

Sub CambiarClave(Clave As String)
    'manager.ResetPassword("1004")
End Sub

Sub ResetearClave
    manager.ResetPassword("1004")
End Sub

Sub btnDisable_LongClick 'Here i like change the lock screen pin
    'manager.ResetPassword("0000")
'    DevicePolicyManager.RunMethod("setResetPasswordToken", Array(ComponentName, token))
    DevicePolicyManager.RunMethod("resetPasswordWithToken", Array(ComponentName, "9876, token, 0")) 'this line give me error
End Sub

I can lock the screen so I know that I gave administrator permissions to the application (also on the lock screen it appears that the device belongs to my organization), the only thing I need is to change the lock screen pin, it is necessary the use of the token?

Thanks again.
 
Upvote 0

Elyza

Member
There was a missing quote in my code. It should be:
B4X:
DevicePolicyManager.RunMethod("resetPasswordWithToken", Array(ComponentName, "9876", token, 0)
Thanks again Erel, now it doesn't give me an error but the code doesn't have any effect ???? (I thought it would change the password to "9876"). Do you have any idea how to change the phone password? (even if it is not with the token).

Thanks one more time for your kind answer.
 
Upvote 0

William Lancee

Well-Known Member
Licensed User
Longtime User
This doesn't have missing quote. But it does have a missing comma at the end. I don't know why you didn't get a syntax error.

B4X:
DevicePolicyManager.RunMethod("resetPasswordWithToken", Array(ComponentName, "9876", token, 0)
 
Upvote 0

Elyza

Member
Not really. Sorry.
Thanks for your answer Erel. I read this in Android documentation:

public boolean resetPassword (String password,
int flags)

This method was deprecated in API level 30.
Please use resetPasswordWithToken(ComponentName, String, byte, int) instead.

And i read this about of resetpassword with Token:

resetPasswordWithToken​

Added in API level 26

public boolean resetPasswordWithToken (ComponentName admin,
String password,
byte[] token,
int flags)
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.

Unlike resetPassword(String, int), this API can change the password even before the user or device is unlocked or decrypted. The supplied token must have been previously provisioned via setResetPasswordToken(ComponentName, byte), and in active state isResetPasswordTokenActive(ComponentName).

The given password must be sufficient for the current password quality and length constraints as returned by getPasswordQuality(android.content.ComponentName) and getPasswordMinimumLength(android.content.ComponentName); if it does not meet these constraints, then it will be rejected and false returned. Note that the password may be a stronger quality, for example, a password containing alphanumeric characters when the requested quality is only numeric.

Calling with a null or empty password will clear any existing PIN, pattern or password if the current password constraints allow it.

On devices not supporting PackageManager#FEATURE_SECURE_LOCK_SCREEN feature, calling this methods has no effect - the password is always empty - and false is returned.
Requires the PackageManager#FEATURE_SECURE_LOCK_SCREEN feature which can be detected using PackageManager.hasSystemFeature(String).

Is there a way to update the Device Manager library?

@William Lancee , thanks for your answer, do you see something wrong in my code?:

B4X:
Sub Process_Globals
    Public manager As AdminManager
End Sub

Sub Globals
    Dim rp As RuntimePermissions
   
    Dim ComponentName As Object = manager.As(JavaObject).GetField("rec")
    Dim DevicePolicyManager As JavaObject = manager.As(JavaObject).GetField("dm")
    Dim sr As SecureRandom 'Encryption library
    Dim token(32) As Byte
End Sub

Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("1")
   
    rp.CheckAndRequest(rp.PERMISSION_RECEIVE_SMS)
    rp.CheckAndRequest(rp.PERMISSION_READ_SMS)
End Sub

Sub Activity_PermissionResult (Permission As String, Result As Boolean)
    If Permission = rp.PERMISSION_RECEIVE_SMS Then
        If Result Then
            Log("Permission 1") 'Only for control
        End If
    Else If Permission = rp.PERMISSION_READ_SMS Then
        If Result Then
            Log("Permission 2") 'Only for control
        End If
    End If
End Sub

Sub Activity_Resume
'    End If
End Sub

Sub btnEnable_Click
    If manager.Enabled = False Then
        manager.Enable("Please give the access.")
    End If
End Sub

Sub btnDisable_Click
    manager.Disable
End Sub

Sub btnLock_Click
    If manager.Enabled Then manager.LockScreen 'This works
End Sub

Sub btnResetPassword_Click
    'manager.ResetPassword("0000") 'This don´t work from Android 30
'    DevicePolicyManager.RunMethod("setResetPasswordToken", Array(ComponentName, token)) 'I comment this line
    DevicePolicyManager.RunMethod("resetPasswordWithToken", Array(ComponentName, "9876", token, 0))
End Sub

I don't want to upload this to the playstore, it's just a personal project. Any help would be good. Greetings and thanks for the responses.

PS: I find this:

"Sharing my solution here, it may help someone in the future.

In my case, I was receiving the same NPE when I wanted to reset the existing device PIN. (assigned by my device owner application)

I figured out that I had to call setResetPasswordToken() method when the PIN is set for the first time, because isResetPasswordTokenActive() was returning false. I solved it as shown below:"

B4X:
if (!devicePolicyManager.isResetPasswordTokenActive(DeviceAdminRcvr.getComponentName(this))) {

            devicePolicyManager.setResetPasswordToken(DeviceAdminRcvr.getComponentName(this), byteValue);
            devicePolicyManager.resetPasswordWithToken(DeviceAdminRcvr.getComponentName(this), firstPassword, byteValue, 0);

} else {
            devicePolicyManager.resetPasswordWithToken(DeviceAdminRcvr.getComponentName(this), newPassword, byteValue, 0);
 }

Maybe something is wrong in my code.
 
Last edited:
Upvote 0

Elyza

Member
Ok, i found this in stackoverflow:

"
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

B4X:
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

B4X:
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

B4X:
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

B4X:
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

B4X:
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

B4X:
@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);
    }
}
 
Upvote 0
Top