平台

RK3288 + Android 7.1

需求

支持人脸解锁

方案说明

使用Smart Lock 中的 "可信面孔" 功能实现人脸解锁

实现步骤

  • 内置GMS(若PUSH进去, 请重置)
    GMS包内容如下:
drwxrwxrwx 2 root root 4096 2013-01-21 17:32 FaceLockdrwxrwxrwx 2 root root 4096 2013-01-21 17:32 GoogleBackupTransportdrwxrwxrwx 2 root root 4096 2013-01-21 17:32 GoogleContactsSyncAdapterdrwxrwxrwx 3 root root 4096 2013-01-21 17:32 GoogleGmsCoredrwxrwxrwx 2 root root 4096 2013-01-21 17:32 GoogleLoginServicedrwxrwxrwx 2 root root 4096 2013-01-21 17:33 GooglePartnerSetupdrwxrwxrwx 3 root root 4096 2013-01-21 17:32 GooglePlaydrwxrwxrwx 2 root root 4096 2013-01-21 17:33 GoogleServicesFramework
  • 确认FaceLock是否已安装
rk3288:/system/priv-app # dumpsys package com.android.facelock                                                                 Permissions:  Permission [com.google.android.gms.auth.permission.FACE_UNLOCK] (e0424d2):    sourcePackage=com.android.facelock    uid=10024 gids=null type=0 prot=signature    perm=Permission{767d9a3 com.google.android.gms.auth.permission.FACE_UNLOCK}    packageSetting=PackageSetting{29984a0 com.android.facelock/10024}Key Set Manager:  [com.android.facelock]      Signing KeySets: 6Packages:  Package [com.android.facelock] (29984a0):    userId=10024    pkg=Package{5866859 com.android.facelock}    codePath=/system/priv-app/FaceLock    resourcePath=/system/priv-app/FaceLock    legacyNativeLibraryDir=/system/priv-app/FaceLock/lib    primaryCpuAbi=null    secondaryCpuAbi=null    versionCode=25 minSdk=15 targetSdk=25    versionName=7.1.2    splits=[base]    apkSigningVersion=2    applicationInfo=ApplicationInfo{bdbbc1e com.android.facelock}    flags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ]    privateFlags=[ PRIVILEGED RESIZEABLE_ACTIVITIES ]    dataDir=/data/user/0/com.android.facelock    supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity]    timeStamp=2019-10-15 10:09:32    firstInstallTime=2019-10-15 10:09:32    lastUpdateTime=2019-10-15 10:09:32    signatures=PackageSignatures{d146cff [e3ca78d8]}    installPermissionsFixed=false installStatus=1    pkgFlags=[ SYSTEM HAS_CODE ALLOW_CLEAR_USER_DATA ]    declared permissions:      com.google.android.gms.auth.permission.FACE_UNLOCK: prot=signature, INSTALLED    requested permissions:      android.permission.CAMERA      com.google.android.gms.auth.permission.FACE_UNLOCK    install permissions:      com.google.android.gms.auth.permission.FACE_UNLOCK: granted=true    User 0: ceDataInode=513 installed=true hidden=false suspended=false stopped=false notLaunched=false enabled=0      runtime permissions:Dexopt state:  [com.android.facelock]    Instruction Set: arm      path: /system/priv-app/FaceLock/FaceLock.apk      status: /data/dalvik-cache/arm/system@priv-app@FaceLock@FaceLock.apk@classes.dex [compilation_filter=interpret-onl      y, status=kOatUpToDate]Compiler stats:  [com.android.facelock]     FaceLock.apk - 252
  • 连接VPN
    内置的GMS包版本较旧, 需要联接GOOGLE更新和支持库等内容.
  • 设置锁屏方式
    设置>安全>屏幕锁定
    要使用smart lock, 需设置屏幕锁定方式为图案/PIN码/密码
  • 打开 可信面孔
    设置>安全>Smart Lock > 可信面孔, 按操作即可

杂项

一些问题
  1. 在GMS更新的过程中, Smart Lock中的选项可能出现的个数在0-3之间, 不稳定
  2. Smart Lock的人脸解锁并不会直接跳过锁屏, 在实际使用过程中, 用户使用电源唤醒设备, 设备开始识别人脸, 识别成功后, 屏幕下方会有解锁动画, 表示已成功解锁, 但 不会 直接进入系统, 需要用户执行上滑动画以完成解锁动作.
  3. 在Android Q(10)开始, GOOGLE出于安全原因, 删除了可信面孔
锁屏相关代码
锁屏程序接收面部识别广播|--frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java//人脸解锁广播    private static final String ACTION_FACE_UNLOCK_STARTED            = "com.android.facelock.FACE_UNLOCK_STARTED";    private static final String ACTION_FACE_UNLOCK_STOPPED            = "com.android.facelock.FACE_UNLOCK_STOPPED";    private final BroadcastReceiver mBroadcastAllReceiver = new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            final String action = intent.getAction();            if (AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED.equals(action)) {                mHandler.sendEmptyMessage(MSG_TIME_UPDATE);            } else if (Intent.ACTION_USER_INFO_CHANGED.equals(action)) {                mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_INFO_CHANGED,                        intent.getIntExtra(Intent.EXTRA_USER_HANDLE, getSendingUserId()), 0));            } else if (ACTION_FACE_UNLOCK_STARTED.equals(action)) {                Trace.beginSection("KeyguardUpdateMonitor.mBroadcastAllReceiver#onReceive ACTION_FACE_UNLOCK_STARTED");                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 1,                        getSendingUserId()));                Trace.endSection();            } else if (ACTION_FACE_UNLOCK_STOPPED.equals(action)) {                mHandler.sendMessage(mHandler.obtainMessage(MSG_FACE_UNLOCK_STATE_CHANGED, 0,                        getSendingUserId()));            } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED                    .equals(action)) {                mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);            } else if (ACTION_USER_UNLOCKED.equals(action)) {                mHandler.sendEmptyMessage(MSG_USER_UNLOCKED);            }        }    };//mHandler 消息处理                case MSG_FACE_UNLOCK_STATE_CHANGED:                    Trace.beginSection("KeyguardUpdateMonitor#handler MSG_FACE_UNLOCK_STATE_CHANGED");                    handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);                    Trace.endSection();                    break;    private void handleFaceUnlockStateChanged(boolean running, int userId) {        mUserFaceUnlockRunning.put(userId, running);        for (int i = 0; i < mCallbacks.size(); i++) {            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();            if (cb != null) {                cb.onFaceUnlockStateChanged(running, userId);            }        }    }|--frameworks/base/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java//空函数    /**     * Called when the state of face unlock changed.     */    public void onFaceUnlockStateChanged(boolean running, int userId) { }|--frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java    private final KeyguardUpdateMonitorCallback mCallback = new KeyguardUpdateMonitorCallback() {//...        @Override        public void onFaceUnlockStateChanged(boolean running, int userId) {            update(false /* updateAlways */);        }}    private void update(boolean updateAlways) {        Trace.beginSection("UnlockMethodCache#update");        int user = KeyguardUpdateMonitor.getCurrentUser();        boolean secure = mLockPatternUtils.isSecure(user);        boolean canSkipBouncer = !secure ||  mKeyguardUpdateMonitor.getUserCanSkipBouncer(user);        boolean trustManaged = mKeyguardUpdateMonitor.getUserTrustIsManaged(user);        boolean trusted = mKeyguardUpdateMonitor.getUserHasTrust(user);        boolean faceUnlockRunning = mKeyguardUpdateMonitor.isFaceUnlockRunning(user)                && trustManaged;        boolean changed = secure != mSecure || canSkipBouncer != mCanSkipBouncer ||                trustManaged != mTrustManaged  || faceUnlockRunning != mFaceUnlockRunning;        if (changed || updateAlways) {            mSecure = secure;            mCanSkipBouncer = canSkipBouncer;            mTrusted = trusted;            mTrustManaged = trustManaged;            mFaceUnlockRunning = faceUnlockRunning;            notifyListeners();        }        Trace.endSection();    }private void notifyListeners() {        for (OnUnlockMethodChangedListener listener : mListeners) {            listener.onUnlockMethodStateChanged();        }    }|--frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java    @Override  // UnlockMethodCache.OnUnlockMethodChangedListener    public void onUnlockMethodStateChanged() {        logStateToEventlog();    }    private void logStateToEventlog() {        boolean isShowing = mStatusBarKeyguardViewManager.isShowing();        boolean isOccluded = mStatusBarKeyguardViewManager.isOccluded();        boolean isBouncerShowing = mStatusBarKeyguardViewManager.isBouncerShowing();        boolean isSecure = mUnlockMethodCache.isMethodSecure();        boolean canSkipBouncer = mUnlockMethodCache.canSkipBouncer();        int stateFingerprint = getLoggingFingerprint(mState,                isShowing,                isOccluded,                isBouncerShowing,                isSecure,                canSkipBouncer);        if (stateFingerprint != mLastLoggedStateFingerprint) {            EventLogTags.writeSysuiStatusBarState(mState,                    isShowing ? 1 : 0,                    isOccluded ? 1 : 0,                    isBouncerShowing ? 1 : 0,                    isSecure ? 1 : 0,                    canSkipBouncer ? 1 : 0);            mLastLoggedStateFingerprint = stateFingerprint;        }    }|--frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.javapublic class KeyguardBottomAreaView extends FrameLayout implements View.OnClickListener,        UnlockMethodCache.OnUnlockMethodChangedListener,        AccessibilityController.AccessibilityStateChangedCallback, View.OnLongClickListener {    @Override    public void onUnlockMethodStateChanged() {        mLockIcon.update();        updateCameraVisibility();    }}|--frameworks/base/services/core/java/com/android/server/trust/TrustManagerService.java     public void updateTrust(int userId, int flags) {        boolean managed = aggregateIsTrustManaged(userId);        dispatchOnTrustManagedChanged(managed, userId);        if (mStrongAuthTracker.isTrustAllowedForUser(userId)                && isTrustUsuallyManagedInternal(userId) != managed) {            updateTrustUsuallyManaged(userId, managed);        }        boolean trusted = aggregateIsTrusted(userId);        boolean changed;        synchronized (mUserIsTrusted) {            changed = mUserIsTrusted.get(userId) != trusted;            mUserIsTrusted.put(userId, trusted);        }        dispatchOnTrustChanged(trusted, userId, flags);        if (changed) {            refreshDeviceLockedForUser(userId);        }    }private void dispatchOnTrustChanged(boolean enabled, int userId, int flags) {        if (DEBUG) {            Log.i(TAG, "onTrustChanged(" + enabled + ", " + userId + ", 0x"                    + Integer.toHexString(flags) + ")");        }        if (!enabled) flags = 0;        for (int i = 0; i < mTrustListeners.size(); i++) {            try {                mTrustListeners.get(i).onTrustChanged(enabled, userId, flags);            } catch (DeadObjectException e) {                Slog.d(TAG, "Removing dead TrustListener.");                mTrustListeners.remove(i);                i--;            } catch (RemoteException e) {                Slog.e(TAG, "Exception while notifying TrustListener.", e);            }        }    }

更多相关文章

  1. Android的屏幕多样性支持
  2. android屏幕监控上下左右滑动
  3. [置顶] android应用框架系列三,兼容性
  4. Android中获得屏幕的尺寸
  5. Android全屏(包含3种隐藏顶部状态栏及标题栏和一种隐藏Android(安
  6. Android屏幕100%适配方案
  7. Android入门:向TextView添加滚动条
  8. Dimension
  9. android 屏幕分辨率获取,等比缩放,屏幕横竖屏设置,屏幕截取

随机推荐

  1. Android心得4.1--文件的保存与读取及文件
  2. .如何避免Android内存泄漏
  3. Android(安卓)NDK C++开发注意事项总结
  4. Android(安卓)再爆新漏洞,9.0 以下所有手
  5. android 开发如何获得第三方应用Widget的
  6. Android(安卓)中读取Excel文件实例详解
  7. Android基于Pull方式解析xml的方法详解
  8. android中采用Pull解析XML文档
  9. “哎哟!蛮吊的” 之 Android(安卓)BroadCa
  10. android 定位的4种方式介绍