首页 > 其他分享 >Android10.0 锁屏分析-KeyguardPatternView图案锁分析

Android10.0 锁屏分析-KeyguardPatternView图案锁分析

时间:2024-07-21 10:29:18浏览次数:15  
标签:mContext Android10.0 java KeyguardPatternView int pattern 锁屏 ACTION return

首先一起看看下面这张图:

通过前面锁屏加载流程可以知道在KeyguardSecurityContainer中使用getSecurityView()根据不同的securityMode inflate出来,并添加到界面上的。
我们知道,Pattern锁所使用的layout是 R.layout.keyguard_pattern_view;

<com.android.keyguard.KeyguardPatternView ...>
...
            <com.android.internal.widget.LockPatternView
                android: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

    @Override
    public 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 {
    ...
        @Override
        public 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() {
                        @Override
                        public 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 */);
                        }
                        @Override
                        public 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 */);
                            }
                        }
                        @Override
                        public 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)at
 SyntheticPasswordllanager. unwrapPasswordBasedSyntheticPassword(SyntheticPasswordllanager. java: 1016
android.os.Binderandroid.os.Binder

标签:mContext,Android10.0,java,KeyguardPatternView,int,pattern,锁屏,ACTION,return
From: https://blog.csdn.net/u010345983/article/details/134877199

相关文章

  • 显卡欺骗器、锁屏宝的代替品,ToDesk虚拟屏功能完美解决
    主机没有显示器?远控电脑需要保持屏幕的高分辨率,但过高容易黑屏?遇到以上情况,人们常常会使用显卡欺骗器或者锁屏宝来解决,就是让显卡认为连接了一个显示器,方便正常使用电脑。但是这往往需要额外给电脑上插入设备,如果是突然急用就很难实现了,有没有人帮忙装显卡欺骗器不说,临时买不买......
  • 删掉雷电模拟器锁屏密码
    如何通过命令行重置雷电模拟器的锁屏密码如果你使用雷电模拟器并遇到了锁屏密码无法解锁的问题,可以通过以下步骤在命令行中重置锁屏密码。这些步骤适用于雷电模拟器9,并假设你的安装目录是C:\leidian\LDPlayer9。步骤1:进入雷电模拟器安装目录首先,打开文件资源管理器并导航到雷......
  • 用C++判断Windows是否锁屏
    点击查看代码#include"windows.h"#include"Windows.h"#include"Wtsapi32.h"#include<tchar.h>#pragmacomment(lib,"WtsApi32.lib")usingnamespacestd;typedefHDESK(WINAPI*PFNOPENDESKTOP)(LPSTR,DWORD,BOO......
  • 苹果iOS 18发布:新增锁屏自定义和应用锁
    今天凌晨1点,iOS18在苹果WWDC24上正式发布。全新的iOS18允许用户自由定义App排列,可以自由选择App颜色主题,并且iOS18升级支持锁屏状态自定义功能,还支持单个App的应用锁,保护用户隐私。与此同时,iOS18对控制中心也进行了升级调整,全新的控制中心更具有扩展性,支持第三方应用控制按......
  • WindTerm锁屏密码
    1、问题现象安装完windterm,时间长不超过会锁屏,然后不知道怎么解锁 2、解决办法默认的密码是空,也就是不用输入,直接回车即可解锁 3、重新设置密码打开锁屏按钮 点击更改主密码 点击更改主密码 然后重新锁屏试下 ......
  • win10设置或更改锁屏密码
    在Windows10中设置锁屏密码可以通过以下步骤完成:1.打开设置点击Windows任务栏左下角的开始菜单(Windows图标),然后点击设置图标(齿轮状),打开Windows设置。2.进入账户设置在Windows设置窗口中,点击账户,进入账户相关设置页面。3.选择登录选项在左侧菜单中选择登录......
  • VBScript编写Windows防止锁屏脚本程序
    <divid="navCategory"><h5class="catalogue">目录</h5><ulclass="first_class_ul"><li><ahref="#_label0">背景介绍</a></li><li><ahref="#_......
  • Ubuntu Desktop - lock screen (锁屏)
    UbuntuDesktop-lockscreen[锁屏]1.SystemSettings->Security&Privacy(安全和隐私)2.SystemSettings->Keyboard->Shortcuts->System3.LockReferences1.SystemSettings->Security&Privacy(安全和隐私)使用Putty远程登录软件,如......
  • C#WPF开发电脑进入锁屏状态退出微信的程序
    前因:当电脑登了微信,手机微信通知设置了”windows微信已登录,手机通知关闭“,这个时候手机的系统通知栏不会通知直接原因:我下班回家,个人习惯是直接锁屏不关机,经常忘记退出微信,然后导致回到家接收不到微信通知,漏掉很多朋友的消息结果:所以想开发一个程序,当我电脑锁屏后直接关掉微信,让......
  • Windows 11 锁屏壁纸问题
    1、打开MicrosoftStore搜索"动态主题"2、安装动态主题并打开3、锁屏并查看效果 ......