android广播实现PIN码设置

摘要:本文通过广播的方式调用系统设置PIN码的流程实现类似锁机的功能,可供开发人员在联网状态下后台推送消息进行锁机/解锁。有需要的同学可以参考PIN码的流程改为密码等其他形式。

1 定义一个广播接收器

广播action:android.intent.action.LOCKDEVICE

boolean extra: lock (true:锁机/false:解锁)

String extra: password (6位数字密码,后续代码会进行合法性检测)

java 复制代码
        <receiver android:name=".LockDeviceReceiver"
                  android:exported="true">
            <intent-filter>    
                <action android:name="android.intent.action.LOCKDEVICE"/>
            </intent-filter>
        </receiver>

2 功能实现

代码部分注释为 android 9之前的实现方式。

java 复制代码
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;

import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.PasswordValidationError.RECENTLY_USED;

import android.app.admin.PasswordMetrics;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.util.Log;

import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.PasswordValidationError;

import java.util.Collections;
import java.util.List;

/**
 * Boot completed receiver. used to reset the app install state every time the
 * device boots.
 *
 */
public class LockDeviceReceiver extends BroadcastReceiver {
    private static String TAG ="LockDeviceReceiver";

    private byte[] mPasswordHistoryHashFactor;
    private LockPatternUtils mLockPatternUtils;
    private LockscreenCredential mChosenPassword;
    private LockscreenCredential mCurrentCredential;

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if ("android.intent.action.LOCKDEVICE".equals(action)) {
            boolean isLock = intent.getBooleanExtra("lock", false);
            String password = intent.getStringExtra("password");
            mLockPatternUtils = new LockPatternUtils(context);
            if (isLock) {
                lockDevice(context, password);
            } else {
                unlockDevice(context, password);
            }
            return;
        }
    }

    private void lockDevice(Context context, String password) {
        mChosenPassword = LockscreenCredential.createPin(password);
        //int mRequestedQuality = mLockPatternUtils.computePasswordQuality(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
        if (password.length() == 6 && validatePassword(mChosenPassword)) {
            //mLockPatternUtils.setCredentialRequiredToDecrypt(false);
            //mLockPatternUtils.saveLockPassword(password, null, mRequestedQuality, UserHandle.myUserId());
            final boolean success = mLockPatternUtils.setLockCredential(
                    mChosenPassword, LockscreenCredential.createNone(), UserHandle.myUserId());
            Log.d(TAG, "lockDevice " + (success ? "success" : "unsuccess"));
        } else {
            Log.d(TAG, "invalid password!");
        }
    }

    private void unlockDevice(Context context, String password) {
        LockscreenCredential credential = LockscreenCredential.createPin(password);
        LockPatternChecker.checkCredential(
            mLockPatternUtils,
            credential,
            UserHandle.myUserId(),
            new LockPatternChecker.OnCheckCallback() {
                @Override
                public void onChecked(boolean matched, int timeoutMs) {
                    if (matched) {
                        //mLockPatternUtils.setSeparateProfileChallengeEnabled(UserHandle.myUserId(), true, credential);
                        //mLockPatternUtils.clearLock(password, UserHandle.myUserId());
                        //mLockPatternUtils.setLockScreenDisabled(true, UserHandle.myUserId());
                        final boolean success = mLockPatternUtils.setLockCredential(
                                LockscreenCredential.createNone(), LockscreenCredential.createPinOrNone(password), UserHandle.myUserId());
                        mLockPatternUtils.setLockScreenDisabled(true, UserHandle.myUserId());
                        Log.d(TAG, "unlockDevice " + (success ? "success" : "unsuccess"));
                    } else {
                        Log.d(TAG, "Password do not match");
                    }
                }
            });
    }

    boolean validatePassword(LockscreenCredential credential) {
        final byte[] password = credential.getCredential();
        List<PasswordValidationError> mValidationErrors = PasswordMetrics.validatePassword(
                new PasswordMetrics(CREDENTIAL_TYPE_NONE), PASSWORD_COMPLEXITY_NONE, true, password);
        if (mValidationErrors.isEmpty() &&  mLockPatternUtils.checkPasswordHistory(
                    password, getPasswordHistoryHashFactor(), UserHandle.myUserId())) {
            mValidationErrors =
                    Collections.singletonList(new PasswordValidationError(RECENTLY_USED));
        }
        return mValidationErrors.isEmpty();
    }

    private byte[] getPasswordHistoryHashFactor() {
        if (mPasswordHistoryHashFactor == null) {
            mPasswordHistoryHashFactor = mLockPatternUtils.getPasswordHistoryHashFactor(
                    mCurrentCredential != null ? mCurrentCredential
                            : LockscreenCredential.createNone(), UserHandle.myUserId());
        }
        return mPasswordHistoryHashFactor;
    }
}

3 其他注意

广播需要在系统管理中添加,避免被拦截。

相关推荐
三少爷的鞋8 小时前
Android 架构七条铁律:架构师真正设计的不是代码,而是秩序
android
海的透彻10 小时前
dockerfile如何快速构建容器(java服务)
java·开发语言
xiangxiongfly91510 小时前
Android GsonFactory总结
android·gson·gsonfactory
code2cat10 小时前
Java工具篇之Gradle:用任务图组织构建与交付
java·开发语言·单元测试·gradle
后台模板学习11 小时前
大模型 Prompt 工程在电商订单系统中的踩坑记录
java·python·prompt
w_zero_one11 小时前
算法--构造
java·数据结构·算法
SL_staff11 小时前
制造业订单交付崩盘?用四层协同框架重建交付可信度(技术实践)
java·产品·全栈
WythePlus11 小时前
Android 14 SELinux策略深度解析
android·安全策略·selinux策略
2501_9432050512 小时前
【366期】Campfire:跨启动器的我的世界联机工具箱
经验分享
SL_staff12 小时前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈