赞
踩
客户设置密码后容易遗忘,反复刷机不符合需求,需要预留一个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中实现。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。