Android10.0 锁屏分析-KeyguardPatternView图案锁分析
首先一起看看下面这张图:

通过前面锁屏加载流程可以知道在KeyguardSecurityContainer中使用getSecurityView()根据不同的securityMode inflate出来,并添加到界面上的。
我们知道,Pattern锁所使用的layout是 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,是一个系统公共控件,下面我们就分析一下这个view是如何处理触摸输入的:
frameworks/base/core/java/com/android/internal/widget/LockPatternView.java
@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();}if (PROFILE_DRAWING) {if (mDrawingProfilingStarted) {Debug.stopMethodTracing();mDrawingProfilingStarted = false;}}return true;}return false;}
几种事件类型:
| 事件 | 简介 |
|---|---|
| ACTION_DOWN | 手指初次触摸到屏幕时触发 |
| ACTION_MOVE | 手指在屏幕上滑动时触发,会多次触发 |
| ACTION_UP | 手指离开屏幕时触发 |
| ACTION_CANCEL | 事件被上层拦截时触发 |
| ACTION_OUTSIDE | 手指不在控件区域时触发 |
不同的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进行局部重绘。
关于历史坐标
为了效率,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()
图案解锁验证
src/com/android/keyguard/KeyguardPatternView.java
private class UnlockPatternListener implements LockPatternView.OnPatternListener {...@Overridepublic void onPatternDetected(final List<LockPatternView.Cell> pattern) {if (DEBUG) Log.d(TAG, "onPatternDetected");mKeyguardUpdateMonitor.setCredentialAttempted();mLockPatternView.disableInput();if (mPendingLockCheck != null) {mPendingLockCheck.cancel(false);}final int userId = KeyguardUpdateMonitor.getCurrentUser();if (pattern.size() < LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {mLockPatternView.enableInput();onPatternChecked(userId, false, 0, false /* not valid - too short */);return;}if (LatencyTracker.isEnabled(mContext)) {LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL);LatencyTracker.getInstance(mContext).onActionStart(ACTION_CHECK_CREDENTIAL_UNLOCKED);}mPendingLockCheck = LockPatternChecker.checkCredential(mLockPatternUtils,LockscreenCredential.createPattern(pattern), // 这里跟进去,会发现将 pattern转化成了 byte[]userId,new LockPatternChecker.OnCheckCallback() {@Overridepublic void onEarlyMatched() {if (DEBUG) Log.d(TAG, "onEarlyMatched");if (LatencyTracker.isEnabled(mContext)) {LatencyTracker.getInstance(mContext).onActionEnd(ACTION_CHECK_CREDENTIAL);}onPatternChecked(userId, true /* matched */, 0 /* timeoutMs */,true /* isValidPattern */);}@Overridepublic void onChecked(boolean matched, int timeoutMs) {if (DEBUG) Log.d(TAG, "onChecked matched:" + matched);if (LatencyTracker.isEnabled(mContext)) {LatencyTracker.getInstance(mContext).onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);}mLockPatternView.enableInput();mPendingLockCheck = null;if (!matched) {onPatternChecked(userId, false /* matched */, timeoutMs,true /* isValidPattern */);}}@Overridepublic void onCancelled() {if (DEBUG) Log.d(TAG, "onCancelled");// We already got dismissed with the early matched callback, so we// cancelled the check. However, we still need to note down the latency.if (LatencyTracker.isEnabled(mContext)) {LatencyTracker.getInstance(mContext).onActionEnd(ACTION_CHECK_CREDENTIAL_UNLOCKED);}}});if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {mCallback.userActivity();mCallback.onUserInput();}}...}
在绘制密码后手指抬起的时候,如果已存的有效点数达到4个及以上,就会使用LockPatternChecker.checkCredential 方法调用 task.execute() 启动一个AsyncTask, 并在doInBackground中调用LockPatternUtils.checkCredential 进行密码验证,此时pattern会被转化成字节形式(LockscreenCredential.createPattern(pattern) 这里跟进去,会发现将 pattern转化成了 byte[])
// LockPatternUtils.java
public static byte[] patternToByteArray(List<LockPatternView.Cell> pattern) {if (pattern == null) {return new byte[0];}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 res;
}
最终和密码锁PIN码锁一样,都是远程调用到LockSettingsService 的 checkCredential 接口进行验证。
Keyguard接收用户输入的密码会通过Binder到framework层的LockSettingsService,LockSettingsService经过一系列调用会通过getGateKeeperService获取GateKeeperService然后调用verifyChallenge方法将密码继续忘底层传递,framework的调用栈如下:
java.lang.Throwab
comandroid.locksettings.1locksettings.LockSettingsService. spBasedDoVerifyCredential(LockSettingsService. java:2724)COT3767075server.ocksettingsLockSettingsService.doVerifyCredentia1(LockSettingsSeryice.java:2020comandroservercom android.server.locksettings.LockSettingsService.doVerifyCredential(LockSettingsService. jaya:1999atcom android.server.locksettings.LockSettingsService. checkCredential(LockSettingsService. java:1972)com android.internal.widget.ILockSettings$Stub.onTransact(ILockSettings.java:542atatexecTransactInternal(Binder.java:1159)execTransact(Binder.java:1123)atSyntheticPasswordllanager. unwrapPasswordBasedSyntheticPassword(SyntheticPasswordllanager. java: 1016
android.os.Binderandroid.os.Binder
相关文章:
Android10.0 锁屏分析-KeyguardPatternView图案锁分析
首先一起看看下面这张图: 通过前面锁屏加载流程可以知道在KeyguardSecurityContainer中使用getSecurityView()根据不同的securityMode inflate出来,并添加到界面上的。 我们知道,Pattern锁所使用的layout是 R.layout.keyguard_pattern_view&a…...
Python 装饰器:函数的函数,代码的艺术
引言 在Python中,装饰器是一种强大的功能,允许程序员在不修改原函数源码的情况下增强或修改函数行为。装饰器本质上是一个接收函数作为参数的高阶函数,并返回一个新的函数或修改原函数的行为。这种机制极大地提高了代码的复用性、可读性和模…...
安全防御2
实验要求: 实验过程: 7,办公区设备可以通过电信链路和移动链路上网(多对多的NAT,并且需要保留一个公网IP不能用来转换): 新建电信区: 新建移动区: 将对应接口划归到各自区域: 新建…...
C语言 ——— 打印水仙花数
目录 何为水仙花数 题目要求 代码实现 何为水仙花数 “水仙花数”是指一个n位数,其各位数字的n次方之和等于该数本身 如:153 1^3 5^3 3^3,则153就是一个“水仙花数” 题目要求 求出0~100000的所有“水仙花数”并输出 代码实现 #i…...
「Conda」在Linux系统中安装Conda环境管理器
在Linux系统中安装Conda环境管理器是一个相对简单的过程。 1. 准备工作 确保你的Linux系统已经更新到最新版本,并安装了基本的开发工具和库。打开终端,执行以下命令: sudo apt-get update sudo apt-get upgrade sudo apt-get install build-essential2. 安装Miniconda或An…...
9.11和9.9哪个大?GPT-4o也翻车了
今天刷到了这个问题,心血来潮去问下chatgpt-4o,没想到疯狂翻车... 第一次问: GPT一开始给出了难绷的解答,让我想起了某短视频软件评论区里对某歌手节目排名的质疑哈哈哈哈哈 但是在接下来的进一步询问和回答中它反应过来了。 第…...
[开源]语雀+Vercel:打造免费个人博客网站
大家好,我是白露。 今天我想和大家分享我的今年的第一个开源项目 —— 基于语雀+Nextjs+Vercel实现免费的博客系统。 简单来说,你在语雀写博客,然后直接一键同步到个人网站上,网站自动部署! 而且,整个过程几乎不需要额外的成本,也不用充值语雀超级会员,hh。这个项目…...
使用ElementUI和element-china-area-data库实现省市区三级联动组件封装
在前端开发中,省市区三级联动是一个常见的需求。今天我们将使用Vue.js和ElementUI组件库,结合element-china-area-data库,来实现一个省市区三级联动的组件。这个组件不仅可以提高用户体验,还能大大简化我们的代码。接下来…...
0718,TCP协议,三次握手,四次挥手
目录 上课喵: TCP(Transmission Control Protocol,传输控制协议)的状态迁移图 TCP连接的状态迁移图 状态迁移说明: 注意: big_htonl.c 字节序转换 addr.c IP地址的转换 作业喵: …...
如何安装Visual Studio Code
Visual Studio Code(简称 VS Code) Visual Studio Code 是一款由微软开发的免费、开源的现代化轻量级代码编辑器。 主要特点包括: 跨平台:支持 Windows、Mac 和 Linux 等主流操作系统,方便开发者在不同平台上保持一…...
vi 编辑器快捷生成 main 函数和基本框架
step1: 执行 sudo vi /etc/vim/vimrc (修改vimrc需要管理员权限:sudo) step2:输入用户密码,回车, 编辑vimrc文件 step3:在尾行输入以下代码(可复制) map mf i#include<stdio.h><ESC>o#includ…...
npm相关指令
切换镜像 腾讯镜像 npm config set registry https://mirrors.cloud.tencent.com/npm/ 淘宝镜像(新版) npm config set registry https://registry.npmmirror.com 淘宝镜像(旧版,已弃用) npm config set regist…...
为什么不要碰自媒体
要是失业了,搞自媒体,可行吗?毫无希望! 如今的自媒体早卷得不成样子了,很难再有机会,根本原因在于几乎没有增量用户的同时,存量用户也不再有剩余时间,全量用户的时间早已被几个自媒…...
酷炫末世意境背景404单页HTML源码
源码介绍 酷炫末世意境背景404单页HTML源码,背景充满着破坏一切的意境,彷佛末世的到来,可以做网站错误页或者丢失页面,将下面的代码放到空白的HTML里面,然后上传到服务器里面,设置好重定向即可 效果预览 …...
PHP 调用 1688 详情 API 接口的实战攻略
在电商领域,获取准确和详细的商品信息对于业务的发展至关重要。1688 作为国内知名的批发采购平台,其详情 API 接口为开发者提供了丰富的数据资源。本文将为您详细介绍如何使用 PHP 调用 1688 详情 API 接口。 一、前期准备 注册 1688 开放平台账号&#…...
SAP ABAP性能优化
1.前言 ABAP作为SAP的专用的开发语言,衡量其性能的指标主要有以下两个方面: 响应时间:对于某项特定的业务请求,系统在收到请求后需要多久返回结果 吞吐量:在给定的时间能,系统能够处理的数据量 2. ABAP语…...
【鸿蒙学习笔记】构建布局・选项卡 (Tabs)
官方文档:选项卡 (Tabs) 目录标题 底部导航顶部导航侧边导航限制导航栏的滑动切换固定导航栏・可滚动导航栏自定义导航栏切换至指定页签 底部导航 Entry Component struct Bujv_tabs {build() {Column() {Tabs({ barPosition: BarPosition.End }) {TabContent() {T…...
独立游戏《星尘异变》UE5 C++程序开发日志5——实现物流系统
目录 一、进出口清单 二、路径计算 三、包裹 1.包裹的数据结构 2.包裹在场景中的运动 四、道路 1.道路的数据结构 2.道路的建造 3.道路的销毁 4.某个有道路连接的建筑被删除 作为一个工厂类模拟经营游戏,各个工厂之间的运输必不可少,本游戏采用的…...
Web开发:<br>标签的作用
br作用 介绍基本用法常见用途注意事项使用CSS替代 介绍 在Web开发中,<br> 标签是一个用于插入换行符的HTML标签。它是“break”的缩写,常用于需要在文本中强制换行的地方。<br> 标签是一个空标签,这意味着它没有结束标签。 基本…...
DVC+Minio
由于参数文件比较大,因此onnx、engine等大文件弃用LFS管理,改用dvc管理: minio就是存储用的 启动miniosudo netstat -ntpl#查看端口号 sudo kill -9 $(sudo lsof -i:5061 -t) 关闭端口对应进程 ./minio server --console-address ":6570…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
区块链技术概述
区块链技术是一种去中心化、分布式账本技术,通过密码学、共识机制和智能合约等核心组件,实现数据不可篡改、透明可追溯的系统。 一、核心技术 1. 去中心化 特点:数据存储在网络中的多个节点(计算机),而非…...
