Android8.1 SystemUI 之图案锁验证流程
2019独角兽企业重金招聘Python工程师标准>>>
在Keyguard之滑动解锁流程一文中,我们已经分析过,不同的安全锁类型是在KeyguardSecurityContainer中使用getSecurityView根据不同的securityMode inflate出来,并添加到界面上的。那么本文我们就来以图案锁为例分析一下,安全锁解锁时的验证流程吧。
图案解锁的滑动事件处理
我们知道,Pattern锁所使用的layout是case Pattern: return R.layout.keyguard_pattern_view;
<com.android.keyguard.KeyguardPatternView ...>...<com.android.internal.widget.LockPatternViewandroid:id="@+id/lockPatternView"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:layout_marginEnd="8dip"android:layout_marginBottom="4dip"android:layout_marginStart="8dip"android:layout_gravity="center_horizontal"android:gravity="center"android:clipChildren="false"android:clipToPadding="false" />...</FrameLayout></com.android.keyguard.KeyguardPatternView>
那么图案解锁的滑动事件处理,就是在LockPatternView,源码位置是android/frameworks/base/core/java/com/android/internal/widget/LockPatternView.java,是一个系统公共控件,下面我们就分析一下这个view是如何处理触摸输入的。
@Overridepublic boolean onTouchEvent(MotionEvent event) {if (!mInputEnabled || !isEnabled()) {return false;}switch(event.getAction()) {case MotionEvent.ACTION_DOWN:handleActionDown(event);return true;case MotionEvent.ACTION_UP:handleActionUp();return true;case MotionEvent.ACTION_MOVE:handleActionMove(event);return true;case MotionEvent.ACTION_CANCEL:if (mPatternInProgress) {setPatternInProgress(false);resetPattern();notifyPatternCleared();}...return true;}return false;}
不同的MotionEvent对应几个不同的handle方法处理,代码行数太多,我们这里大致总结如下
ACTION_DOWN(handleActionDown):根据触摸事件的坐标,使用算法detectAndAddHit(x, y)获取是否有命中的点,如果有,会调用addCellToPattern将命中的Cell添加到mPattern中,后即回调mOnPatternListener.onPatternStart()通知监听器,KeyguardPatternView实现并监听了OnPatternListener,做了清除安全提示内容的动作。另外计算需要重绘区域,并调用invalidate进行局部重绘。
ACTION_MOVE(handleActionMove):在这里 LockPatternView会对所有的历史坐标加当前事件坐标遍历
for (int i = 0; i < historySize + 1; i++)
,获取命中点,另外如果ACTION_DOWN时没有获取到命中点,流程同上面的ACTION_UP,然后也会回调mOnPatternListener.onPatternStart()。最后会把所有motionevent对应的重绘区域进行union,并调用invalidate进行局部重绘。
关于MotionEvent的历史坐标getHistoricalX,getHistoricalY的解释可以参考developer文档-->MotionEvent
关于历史坐标
为了效率,Android系统在处理ACTION_MOVE事件时会将连续的几个多触点移动事件打包到一个MotionEvent对象中。我们可以通过getX(int)和getY(int)来获得最近发生的一个触摸点事件的坐标,然后使用getHistorical(int,int)和getHistorical(int,int)来获得时间稍早的触点事件的坐标,二者是发生时间先后的关系。所以,我们应该先处理通过getHistoricalXX相关函数获得的事件信息,然后在处理当前的事件信息。
for (int i = 0; i < historySize + 1; i++) {final float x = i < historySize ? event.getHistoricalX(i) : event.getX();final float y = i < historySize ? event.getHistoricalY(i) : event.getY();...}
ACTION_UP(handleActionUp):如果mPattern不为空的话,会重置mPatternInProgress,取消动画,然后回调mOnPatternListener.onPatternDetected(final List<LockPatternView.Cell> pattern),这时候就开始图案解锁的验证了。
ACTION_CANCEL:重置pattern状态,回调mOnPatternListener.onPatternCleared()
关于ACTION_CANCEL的产生和事件回传你一定要知道的事
在当前控件(子控件)收到前驱事件(ACTION_MOVE或者ACTION_MOVE)后,它的父控件突然插手(interceptTouchEvent)截断事件的传递,这时当前控件就会收到ACTION_CANCEL,收到此事件后,不管子控件此时返回true或者false,都认为这一个动作已完成,不会再回传到父控件的OnTouchEvent中处理,同时后续事件,会通过dispatchEvent方法直接传送到父控件这里来处理。
那么有的朋友就要问了,不是说如果子控件的OnTouchEvent返回false,表明事件未被处理,是回传到父控件去处理的吗? 其实,只有ACTION_DOWN事件才可以被回传,ACTION_MOVE和ACTION_UP事件会跟随ACTION_DOWN事件,即ACTION_DOWN是哪个控件处理的,后续事件都传递到这里,不会上抛到父控件,ACTION_CANCEL也不能回传。
结论:ACTION_CANCEL事件是收到前驱事件后,后续事件被父控件拦截的情况下产生,onTouchEvent的事件回传到父控件只会发生在ACTION_DOWN事件中
图案解锁验证
src/com/android/keyguard/KeyguardPatternView.java
private class UnlockPatternListener implements LockPatternView.OnPatternListener {...@Overridepublic void onPatternDetected(final List<LockPatternView.Cell> pattern) {// 禁用事件输入,取消前面的AsyncTaskmLockPatternView.disableInput();if (mPendingLockCheck != null) {mPendingLockCheck.cancel(false);}final int userId = KeyguardUpdateMonitor.getCurrentUser();// 如果连接的点小于4个,作为无效密码if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {mLockPatternView.enableInput();onPatternChecked(userId, false, 0, false /* not valid - too short */);return;}mPendingLockCheck = LockPatternChecker.checkPattern(mLockPatternUtils,pattern,userId,new LockPatternChecker.OnCheckCallback() {...});if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {mCallback.userActivity();}}...}
checkPattern方法中构造了一个AsyncTask,并start()。
在onPreExecute()中复制了一份pattern,用ArrayList包装
patternCopy = new ArrayList(pattern);
关于AsyncTask的cancel(boolean mayInterruptIfRunning) 方法
先说结论,单独使用cancel不会像你想的那样好好工作。
如果你调用了AsyncTask的cancel(false),doInBackground()仍然会执行到方法结束,只是不会去调用onPostExecute()方法。但是实际上这是让应用程序执行了没有意义的操作。
那么是不是我们调用cancel(true)前面的问题就能解决呢?并非如此。如果mayInterruptIfRunning设置为true,会使任务尽早结束,但是如果的doInBackground()有不可打断的方法会失效。
可见.cancel()是给AsyncTask设置一个"canceled"的状态,那么想要终止异步任务,就需要在异步任务当中结束。
// Task被取消了,马上退出
if(isCancelled()) return null;
.......
// Task被取消了,马上退出
if(isCancelled()) return null;
}
在doInBackground()中LockPatternUtils登场了,图案密码的验证,就是调用了LockPatternUtils的checkPattern方法
return utils.checkPattern(patternCopy, userId, callback::onEarlyMatched);
下面我们来看一下checkPattern方法的定义:
android/frameworks/base/core/java/com/android/internal/widget/LockPatternUtils.java
/*** Check to see if a pattern matches the saved pattern. If no pattern exists,* always returns true.* @param pattern The pattern to check.* @return Whether the pattern matches the stored one.*/public boolean checkPattern(List<LockPatternView.Cell> pattern, int userId,@Nullable CheckCredentialProgressCallback progressCallback)throws RequestThrottledException {throwIfCalledOnMainThread();return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId,progressCallback);}
LockPatternUtils首先会把pattern使用patternToString算法转换成字符串,之后调用checkCredential进行验证
在LockPatternUtils中还有一个checkPassword方法,对应的是PIN码/密码,所以图案锁/密码锁/PIN码锁的验证流程到这里开始就一致了。
/*** Serialize a pattern.* @param pattern The pattern.* @return The pattern in string form.*/public static String patternToString(List<LockPatternView.Cell> pattern) {if (pattern == null) {return "";}final int patternSize = pattern.size();byte[] res = new byte[patternSize];for (int i = 0; i < patternSize; i++) {LockPatternView.Cell cell = pattern.get(i);res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1');}return new String(res);}
KeyguardPINView/KeyguardPasswordView/KeyguardSimPinView/KeyguardSimPukView
都是继承自KeyguardAbsKeyInputView,用于密码验证的方法是verifyPasswordAndUnlock()
其中,KeyguardSimPinView和KeyguardSimPukView重写了该方法,所以有自己独特的验证方式。
而KeyguardPasswordView和KeyguardPINView都是使用LockPatternUtils的checkPassword进行密码验证
checkPassword和checkPassword都会去调用checkCredential方法
private boolean checkCredential(String credential, int type, int userId,@Nullable CheckCredentialProgressCallback progressCallback)throws RequestThrottledException {try {VerifyCredentialResponse response = getLockSettings().checkCredential(credential, type,userId, wrapCallback(progressCallback));if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {return true;} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {throw new RequestThrottledException(response.getTimeout());} else {return false;}} catch (RemoteException re) {return false;}}
这里的getLockSettings()是什么呢?
ILockSettings service = ILockSettings.Stub.asInterface( ServiceManager.getService("lock_settings"));
原来是获得了LockSettingService的IPC接口,asInterface获取到aidl的Stub.Proxy对象,对本地数据进行封包,进行进程间通信。到这里我们明白了,原来密码的验证,最终是在LockSettingService中进行的。
android/frameworks/base/services/core/java/com/android/server/locksettings/LockSettingsService.java
@Overridepublic VerifyCredentialResponse checkCredential(String credential, int type, int userId,ICheckCredentialProgressCallback progressCallback) throws RemoteException {checkPasswordReadPermission(userId);VerifyCredentialResponse response = doVerifyCredential(credential, type, false, 0, userId, progressCallback);if ((response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) &&(userId == UserHandle.USER_OWNER)) {retainPassword(credential);}return response;}
到这里, 我们的图案锁解锁流程就算是梳理清楚了。
总结一下:在绘制密码后手指抬起的时候,如果已存的有效点数达到4个及以上,就会使用LockPatternChecker.checkPattern方法启动一个AsyncTask, 并在doInBackground中调用LockPatternUtils.checkPattern进行密码验证,此时pattern会被转化成字符串形式,最终和密码锁PIN码锁一样,都是远程调用到LockPatternService的checkCredential接口进行验证。在整个操作过程中,mOnPatternListener被用于通知LockPatternView进行安全锁提示内容和Pattern状态的刷新。
checkCredential的具体算法逻辑以及LockPatternUtils和LockSettingsService中还有很多与安全锁加锁/解锁/锁状态判断相关的接口,后面我们会单独进行分析:)。
本文章已经独家授权ApeClub公众号使用。
转载于:https://my.oschina.net/u/920274/blog/3013498
Android8.1 SystemUI 之图案锁验证流程相关推荐
- android keyguard,Android8.1 SystemUI Keyguard之指纹解锁流程
手指在指纹传感器上摸一下就能解锁,Keyguard是怎么做到的呢? 下面我们就跟着源码,解析这整个过程. 何时开始监听指纹传感器? 先来看下IKeyguardService这个binder接口有哪些回 ...
- android指纹解锁动画,Android8.1 SystemUI Keyguard之指纹解锁流程
手指在指纹传感器上摸一下就能解锁,Keyguard是怎么做到的呢? 下面我们就跟着源码,解析这整个过程. 何时开始监听指纹传感器? 先来看下IKeyguardService这个binder接口有哪些回 ...
- Android 9.0 SystemUI 锁屏流程分析
1.锁屏界面显示的流程 2.按键灭屏 -> 按键亮屏 对于Key事件,InputDispatcher在分发之前会先将事件上发到PhoneWindowManager中,可以进行拦截,故从Phone ...
- AndroidICS4.0----LockScreen锁屏流程【Android源码解析九】
先来说说LockScreen分类: 一.无锁屏: 二.锁屏: 1.UnLockScreen: 图案锁. PIN锁, 密码锁: 2.LockScreen: 波纹锁: 转载请表明出处:http://blo ...
- 教你破解Android手机图案锁
2019独角兽企业重金招聘Python工程师标准>>> 我们在之前的<忘记了手机锁怎么办>这篇文章中已经介绍了暴力删除手机图形锁.密码锁的方法.今天介绍另外一种破解图案锁 ...
- 安全锁界面,防止底部上滑触发人脸解锁与绘制图案锁冲突
原生在KeyguardSecurityContainer.java中,当滑动至安全锁界面时,如果设置了人脸解锁,会上滑再次触发人脸解锁. 此时若是图案解锁,会时有发生图案锁绘制与上滑触发人脸解锁冲突的 ...
- adb删除图案锁屏密码
1.前提 1.1环境是Le X620 安卓6.0 由于自己手机设置了隐私锁,但是隐私锁的密码忘记了,锁屏密码还记得,想关闭图案锁屏密码,但是提示有隐私锁不让关闭,但是隐私锁密码又忘记了,所以直接adb ...
- Android中图案锁的实现
原文地址:http://blog.csdn.net/liusiqian0209/article/details/50372448 很多品牌的Android手机都实现了图案解锁屏幕的功能,有些应用程序出 ...
- Android4.0 4.1Keyguard锁屏流程梳理
一直想要整理一下keyguard(锁屏)模块的相关流程,由于各种原因总是没真正着手开始做,一直拖也不是个办法,所以就索性开始了. 这篇内容会比较偏分析,所以闲话就少扯点了. 锁屏模块位于framewo ...
最新文章
- mysql正斜杠_MySQL中的正斜杠和反斜杠 | | 数据库系统概论(字符匹配)
- avplayer VS2008编译
- CentOS 6.5下Redis安装配置记录
- linux系统怎么清理,linux系统怎么清理废物清理
- css 中 border 断线解决,简单实用
- SpringNBoot日志配置
- Java乘法计算错误,Java JRE致命错误:乘法过多
- python中函数用法教程_Python中zip()函数用法实例教程
- sqlserver 组内排序
- iText 7 基础
- 三星Galaxy S4 刷入CWM Recovery和获取ROOT教程
- 海洋CMS插件-内置接口的海洋CMS插件
- 杭州心田花开:70首人教版小学语文须掌握古诗词(附译文)
- Vue 路由 导航守卫(全局守卫、组件内守卫、路由独享守卫)
- lpx寒假作业案例10
- cleanmymac4.12最新版下载安装教程
- linux界面安装weblogic12c,Linux安装WebLogic12c
- 存储系统性能影响因素(2)---固态硬盘
- Hey 朋友们好久不见。
- POJ 3253 Fence Repair(修篱笆)
热门文章
- sqlserver批量(部分)导出一张表中的数据
- 网站流量排名分析:SEO如何诊断排名不佳的页面!
- IBM服务器硬盘灯不正常闪烁的解决办法(新硬盘绿灯闪烁)
- 用JS制作一个简易GPA计算器
- Qt QSet 详解:从底层原理到高级用法
- error: conflicting declaration ‘typedef struct LZ4_stream_t LZ4_stream_t’
- 简单介绍十几款常用的画架构图流程图的软件
- 对一些内存名词术语的解释(bank ECC等)——转载
- 系统文件host的作用
- 市北·GMIS 2019 全球数据智能峰会全记录