安卓11之adb命令清除锁屏密码
安卓11清除锁屏密码
需求说明
客户设置密码后容易遗忘,反复刷机不符合需求,需要预留一个adb命令去直接清除掉锁屏密码。
为什么不直接删除对应文件
安卓11找不到对应的.key文件了,根据老的版本,大概8.0之前是有.key文件去管理锁屏密码的,但是现在没有了
修改
原理
制造假数据(空的数据)去覆盖掉,然后在通过方法去清除掉空数据
设置假数据去覆盖掉旧的密码
路径:
frameworks\base\core\java\com\android\internal\widget\LockPatternUtils.java
代码:
/**
* Save a new lockscreen credential.
*
* <p> This method will fail (returning {@code false}) if the previously saved credential
* provided is incorrect, or if the lockscreen verification is still being throttled.
*
* @param newCredential The new credential to save
* @param savedCredential The current credential
* @param userHandle the user whose lockscreen credential is to be changed
*
* @return whether this method saved the new password successfully or not. This flow will fail
* and return false if the given credential is wrong.
* @throws RuntimeException if password change encountered an unrecoverable error.
* @throws UnsupportedOperationException secure lockscreen is not supported on this device.
* @throws IllegalArgumentException if new credential is too short.
*/
public boolean setLockCredential(@NonNull LockscreenCredential newCredential,
@NonNull LockscreenCredential savedCredential, int userHandle) {
if (!hasSecureLockScreen()) {
throw new UnsupportedOperationException(
"This operation requires the lock screen feature.");
}
newCredential.checkLength();
try {
if (!getLockSettings().setLockCredential(newCredential, savedCredential, userHandle)) {
return false;
}
} catch (RemoteException e) {
throw new RuntimeException("Unable to save lock password", e);
}
onPostPasswordChanged(newCredential, userHandle);
return true;
}
这个类怎么用呐?
直接百度翻译注释:
这个方法是用来保存新的锁屏凭证
这个方法有三个参数,分别代表:
新的锁屏凭证,旧的锁屏凭证,要修改凭证的用户
这里提到了LockscreenCredential这个类,前面两个参数是基于这个修改的
路径:
frameworks\base\core\java\com\android\internal\widget\LockscreenCredential.java
新的锁屏凭证:
这里我们需要的是一个空的密码凭证,对应方法为:
/**
* Creates a LockscreenCredential object representing empty password.
*/
public static LockscreenCredential createNone() {
return new LockscreenCredential(CREDENTIAL_TYPE_NONE, new byte[0]);
}
很好,这里调用了自身的构造方法,返回一个基于自己的对象,这个构造方法怎么说
百度翻译注释结果:
创建表示给定模式的LockscreenCredential对象
第一个参数是一个类似标识符的东西,在这个类中通过对应标识去做不同的事情
private LockscreenCredential(int type, byte[] credential) {
Objects.requireNonNull(credential);
if (type == CREDENTIAL_TYPE_NONE) {
Preconditions.checkArgument(credential.length == 0);
} else {
// Do not allow constructing a CREDENTIAL_TYPE_PASSWORD_OR_PIN object.
Preconditions.checkArgument(type == CREDENTIAL_TYPE_PIN
|| type == CREDENTIAL_TYPE_PASSWORD
|| type == CREDENTIAL_TYPE_PATTERN);
Preconditions.checkArgument(credential.length > 0);
}
mType = type;
mCredential = credential;
}
看代码得知后面的参数是指这个的存放的长度,就相当于预留多少内存空间去存放,这里createNone给的是new byte[0],走if上面,不细究,喜欢看的自己去细看源码。
这样我们就大概可以知道直接LockscreenCredential.createNone()就可以拿到一个新的空的锁屏凭证了,(这里注一个小知识:被static修饰的方法可以直接调用,不需要new对象,且只能被继承,不能被重写)。
旧的锁屏凭证
旧的锁屏凭证这个就比较麻烦了,主要是有三种(除了无和滑动),这三种分别代表图案,PIN码和密码。
回到LockscreenCredential这个类,先说密码的锁屏凭证
/**
* Creates a LockscreenCredential object representing the given alphabetic password.
* If the supplied password is empty, create an empty credential object.
*/
public static LockscreenCredential createPasswordOrNone(@Nullable CharSequence password) {
if (TextUtils.isEmpty(password)) {
return createNone();
} else {
return createPassword(password);
}
}
首先是空的凭证和非空凭证的判断,接下来找非空的判断走法
/**
* Creates a LockscreenCredential object representing the given alphabetic password.
*/
public static LockscreenCredential createPassword(@NonNull CharSequence password) {
return new LockscreenCredential(CREDENTIAL_TYPE_PASSWORD,
charSequenceToByteArray(password));
}
传个密码就好了。嗯,当然,这就要知道安卓系统一般保存这种数据都是通过数据库的,既然可以写入,自然就可以拿到了,当然,如果没有怎么办,我们就自己做一个。
先拿密码和PIN码为例
路径:
vendor\mediatek\proprietary\packages\apps\MtkSettings\src\com\android\settings\password\ChooseLockPassword.java
没有这个路径怎么办,老办法找对应类就好了
Settings.System.putString(getContext().getContentResolver(), "lock_password", passwordText.toString());
这句代码加在handleNext();方法里面,
为什么??
看调用:
protected void onNextButtonClick(View view) {
handleNext();
}
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// Check if this was the result of hitting the enter or "done" key
if (actionId == EditorInfo.IME_NULL
|| actionId == EditorInfo.IME_ACTION_DONE
|| actionId == EditorInfo.IME_ACTION_NEXT) {
handleNext();
return true;
}
return false;
}
这里干了啥,点击按键的监听,什么按键?
很显然,FooterButton,这里是通过导包拿的,应该是自定义的一个控件,主要说明,为什么在这里面调用,这个就是输入密码的时候的下一步按钮的事件监听;
好了,这里我们还需要导包
import android.provider.Settings;
这里我们已经加上了在输入密码和PIN码的,接下来就是图案密码了
byte[] pBytes = LockPatternUtils.patternToByteArray(pattern);
String res = new String(pBytes);
Settings.System.putString(getContext().getContentResolver(), "lock_password", res.toString());
加在onPatternDetected(List<LockPatternView.Cell> pattern);方法里面,这里也需要导包
和上面的密码和PIN码导的包一样
由于这两个类都是Activity,这样我们需要考虑到这个值是否会受到生命周期的影响,比如说在切换横竖屏的时候,由于这个值不是固定的xml文件中的存在,且没有对应id去控制,所以,我们需要在onSaveInstanceState()中去保存
if (mCurrentCredential != null) {
LockscreenCredential currentCredential_dup = mCurrentCredential.duplicate();
outState.putParcelable(KEY_CURRENT_CREDENTIAL, currentCredential_dup);
}
这样我们就创建好了一个旧的密码的存储方式,且保存了旧的凭证的临时数据。
我们可以通过下面的方式拿到密码,且知道图案密码的保存值也是被转化的password
String password = Settings.System.getString(mContext.getContentResolver(), "lock_password");
这样就可以拿到旧的锁屏凭证之密码凭证了。
PIN码的拿法和这个一致,只是方法里面的参数换成了CharSequence pin
我们拿到密码是针对锁屏所有的,所以传入的参数还是password,只是方法换成了
public static LockscreenCredential createPinOrNone(@Nullable CharSequence pin) {
if (TextUtils.isEmpty(pin)) {
return createNone();
} else {
return createPin(pin);
}
}
接下来就是图案密码了
/**
* Creates a LockscreenCredential object representing the given pattern.
*/
public static LockscreenCredential createPattern(@NonNull List<LockPatternView.Cell> pattern) {
return new LockscreenCredential(CREDENTIAL_TYPE_PATTERN,
LockPatternUtils.patternToByteArray(pattern));
}
这里用同样的方法去将password转化成需要的参数。
这里需要借助LockPatternUtils的byteArrayToPattern()方法,先将password转化成byte数组,以byte数组转化成pattern,最后通过createPattern()方法拿到旧的锁屏凭证之图案。
要修改凭证的用户
int userId = UserHandle.USER_SYSTEM;
这里直接拿系统用户就可以了
这个是UserHandle的类,由于文章篇幅过长,不做阐述,自己去看详细代码
http://t.csdn.cn/2KVw0
现在就已经完成了新的空密码替换旧的密码了,我们还需要让锁屏界面不显示,也就是切换成无的状态
这里用的是LockPatternUtils的setLockScreenDisabled(boolean disable, int userId);方法
/**
* Disable showing lock screen at all for a given user.
* This is only meaningful if pattern, pin or password are not set.
*
* @param disable Disables lock screen when true
* @param userId User ID of the user this has effect on
*/
public void setLockScreenDisabled(boolean disable, int userId) {
setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
}
以下就是清除锁屏密码的全部代码
//清除锁屏密码
public void clearLockscreen(){
String password = Settings.System.getString(mContext.getContentResolver(), "lock_password");
int userId = UserHandle.USER_SYSTEM;
int type = mLockPatternUtils.getCredentialTypeForUser(userId);
if(type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD){
mLockPatternUtils.setLockCredential(LockscreenCredential.createNone(),
LockscreenCredential.createPasswordOrNone(password), userId);
mLockPatternUtils.setLockScreenDisabled(true, userId);
ShutdownThread.reboot(mContext,"userrequested",false);
}else if(type == LockPatternUtils.CREDENTIAL_TYPE_PIN){
mLockPatternUtils.setLockCredential(LockscreenCredential.createNone(),
LockscreenCredential.createPinOrNone(password), userId);
mLockPatternUtils.setLockScreenDisabled(true, userId);
ShutdownThread.reboot(mContext,"userrequested",false);
}else if(type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN){
byte[] pBytes = password.getBytes();
mLockPatternUtils.setLockCredential(LockscreenCredential.createNone(),
LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(pBytes)), userId);
mLockPatternUtils.setLockScreenDisabled(true, userId);
ShutdownThread.reboot(mContext,"userrequested",false);
}
}
这里用了ShutdownThread的reboot方法,这个方法是为了请求干净关机,等待子系统清理其
*状态等,必须从其UI所在的循环器线程调用。如果不使用这个方法会无效。
而type是为了筛选3种不同的密码实现方式。
方法已经给了,则adb命令可以通过广播去实现,这里不做具体阐述,注意在导包的时候可能由于不处在一个项目里面而失败,建议在PhoneWindowManager.java中实现。
更多推荐
所有评论(0)