Как программно сбросить пароль экрана блокировки на Android SDK 26 или выше

В своем приложении я хочу изменить пароль экрана блокировки программно. Поэтому я написал этот метод для сброса пароля:

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

Когда я вызываю метод, я получаю эту ошибку на своем устройстве под управлением 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)
...

Прежде чем я вызову этот метод, я получаю права администратора устройства с помощью этого метода.

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

Моя политика выглядит так

<?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>

person dudi    schedule 30.08.2019    source источник


Ответы (2)


Пожалуйста, ознакомьтесь с документацией, там четко указано, что:

Вызывается владельцем устройства или профиля для принудительной установки нового пароля разблокировки устройства или вызова управляемого профиля для текущего пользователя. Это вступает в силу немедленно.

Из вашего кода не похоже, что вы являетесь «владельцем устройства или профиля»; пожалуйста, не путайте это с «администратором устройства», которым кажутся ваши приложения (или пытается не быть уверенным, действительно ли оно успешно из вашего кода).

person BBB    schedule 05.09.2019

Для меня это решение сработало:

Сначала определите права администратора устройства

policies.xml

<?xml version="1.0" encoding="utf-8"?> <device-admin> <uses-policies> <reset-password/> </uses-policies> </device-admin>

Затем создайте класс, расширяющий 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);
}

}

Получите разрешение администратора устройства с помощью этой функции в вашем 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);
}

Затем подготовьте рабочий профиль для своего приложения в 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();
    }
}

После этого установите пакет приложения в рабочий профиль

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

Создайте метод для генерации случайных токенов паролей

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

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

 @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);
    }
}
person dudi    schedule 05.09.2019