Android MTK 屏下指纹的调试过程记录

Demo链接 ----->  https://download.csdn.net/download/u011694328/89118346

一些品牌手机都有了屏下指纹的功能,还算是个比较新颖的功能,最近有项目需要使用屏下指纹, 使用的是汇顶(Goodix)的指纹方案,经过坚难尝试,终于实现了屏下指纹录入与解锁,下面记录一些知识要点,同时分享给遇到相同问题的。

 1, 自从Android 12 以后, SystemUI 里是自带了屏下指纹方案的. 具体代码是在 frameworks\base\packages\SystemUI\src\com\android\systemui\biometrics ,所有以 Udfps 开头的类均是跟屏下指纹相关。如果要打开自带的屏下指纹UI ,需要在 frameworks 里设置指纹传感器的 X轴 , Y轴 ,半径大小,贴上详细代码。

路径 -----> frameworks/base/services/core/java/com/android/server/biometrics/AuthService.java

final int[] udfpsProps = getContext().getResources().getIntArray(com.android.internal.R.array.config_udfps_sensor_props);

重要的是 config_udfps_sensor_props 数组 , 默认的是空,下面是原始的代码

    <!-- The properties of a UDFPS sensor in pixels, in the order listed below: --><integer-array name="config_udfps_sensor_props" translatable="false" ><!--<item>sensorLocationX</item><item>sensorLocationY</item><item>sensorRadius</item>--></integer-array>

 //  The existence of config_udfps_sensor_props indicates that the sensor is UDFPS.

注释的意思是如果这个数组存在,表明是屏下指纹 。 这里要根据屏幕上传感器的位置来确定 X Y R. 指纹方案商会提供。默认的指纹如下图。

2 , 打开传感器后,调好正确的位置,下面是到设置里录入指纹。

代码路径 packages\apps\Settings\src\com\android\settings\biometrics\fingerprint\FingerprintEnrollEnrolling.java

下面贴上我修改过的代码, 

package com.android.settings.biometrics.fingerprint;import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.drawable.Animatable2;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Bundle;
import android.os.Process;
import android.os.VibrationAttributes;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.settings.R;
import com.android.settings.biometrics.BiometricEnrollSidecar;
import com.android.settings.biometrics.BiometricUtils;
import com.android.settings.biometrics.BiometricsEnrollEnrolling;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.display.DisplayDensityUtils;
import com.airbnb.lottie.LottieAnimationView;
import com.google.android.setupcompat.template.FooterBarMixin;
import com.google.android.setupcompat.template.FooterButton;
import com.google.android.setupcompat.util.WizardManagerHelper;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.List;//import com.goodix.fingerprint.ShenzhenConstants;
//import com.goodix.fingerprint.service.GoodixFingerprintManager;public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {private static final String TAG = "zgyFp";static final String TAG_SIDECAR = "sidecar";private static final int PROGRESS_BAR_MAX = 10000;private static final int STAGE_UNKNOWN = -1;private static final int STAGE_CENTER = 0;private static final int STAGE_GUIDED = 1;private static final int STAGE_FINGERTIP = 2;private static final int STAGE_LEFT_EDGE = 3;private static final int STAGE_RIGHT_EDGE = 4;@IntDef({STAGE_UNKNOWN, STAGE_CENTER, STAGE_GUIDED, STAGE_FINGERTIP, STAGE_LEFT_EDGE, STAGE_RIGHT_EDGE})@Retention(RetentionPolicy.SOURCE)private @interface EnrollStage {}/*** If we don't see progress during this time, we show an error message to remind the users that* they need to lift the finger and touch again.*/private static final int HINT_TIMEOUT_DURATION = 2500;private static final VibrationEffect VIBRATE_EFFECT_ERROR = VibrationEffect.createWaveform(new long[] {0, 5, 55, 60}, -1);private static final VibrationAttributes FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES = VibrationAttributes.createForUsage(VibrationAttributes.USAGE_ACCESSIBILITY);private FingerprintManager mFingerprintManager;private boolean mCanAssumeUdfps;@Nullable private ProgressBar mProgressBar;private ObjectAnimator mProgressAnim;private TextView mDescriptionText;private TextView mErrorText;private Interpolator mFastOutSlowInInterpolator;private Interpolator mLinearOutSlowInInterpolator;private Interpolator mFastOutLinearInInterpolator;private boolean mAnimationCancelled;@Nullable private AnimatedVectorDrawable mIconAnimationDrawable;@Nullable private AnimatedVectorDrawable mIconBackgroundBlinksDrawable;private boolean mRestoring;private Vibrator mVibrator;private boolean mIsSetupWizard;private AccessibilityManager mAccessibilityManager;private boolean mIsAccessibilityEnabled;private LottieAnimationView mIllustrationLottie;private boolean mHaveShownUdfpsTipLottie;private boolean mHaveShownUdfpsLeftEdgeLottie;private boolean mHaveShownUdfpsRightEdgeLottie;private boolean mShouldShowLottie;private OrientationEventListener mOrientationEventListener;private int mPreviousRotation = 0;//    private GoodixFingerprintManager mGoodixFingerprintManager;
//    private ImageView mFingerprintAnimator;
//    private CircleView mCircleView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;getWindow().getDecorView().setSystemUiVisibility(flags);mFingerprintManager = getSystemService(FingerprintManager.class);final List<FingerprintSensorPropertiesInternal> props = mFingerprintManager.getSensorPropertiesInternal();mCanAssumeUdfps = props.size() == 1 && props.get(0).isAnyUdfpsType();mAccessibilityManager = getSystemService(AccessibilityManager.class);mIsAccessibilityEnabled = mAccessibilityManager.isEnabled();listenOrientationEvent();setContentView(R.layout.fingerprint_enroll_enrolling_base); mIsSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());updateTitleAndDescription();//            mGoodixFingerprintManager = GoodixFingerprintManager.getFingerprintManager(this);
//            
//            getMainThreadHandler().postDelayed(mDelayedSendCmd, getFinishDelay());DisplayDensityUtils displayDensity = new DisplayDensityUtils(getApplicationContext());int currentDensityIndex = displayDensity.getCurrentIndex();final int currentDensity = displayDensity.getValues()[currentDensityIndex];final int defaultDensity = displayDensity.getDefaultDensity();mShouldShowLottie = defaultDensity == currentDensity;boolean isLandscape = BiometricUtils.isReverseLandscape(getApplicationContext()) || BiometricUtils.isLandscape(getApplicationContext());updateOrientation((isLandscape ? Configuration.ORIENTATION_LANDSCAPE : Configuration.ORIENTATION_PORTRAIT));mErrorText = findViewById(R.id.error_text);mProgressBar = findViewById(R.id.fingerprint_progress_bar);
//        mFingerprintAnimator = findViewById(R.id.fingerprint_image_hint);
//        mCircleView = findViewById(R.id.circle_view);mVibrator = getSystemService(Vibrator.class);//        setSensorAreaOnTouchListener(mFingerprintAnimator);final LayerDrawable fingerprintDrawable = mProgressBar != null ? (LayerDrawable) mProgressBar.getBackground() : null;if (fingerprintDrawable != null) {mIconAnimationDrawable = (AnimatedVectorDrawable) fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_animation);mIconBackgroundBlinksDrawable = (AnimatedVectorDrawable) fingerprintDrawable.findDrawableByLayerId(R.id.fingerprint_background);mIconAnimationDrawable.registerAnimationCallback(mIconAnimationCallback);}mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.fast_out_slow_in);mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.linear_out_slow_in);mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(this, android.R.interpolator.fast_out_linear_in);mRestoring = savedInstanceState != null;}//    private void setSensorAreaOnTouchListener(View view) {
//        view.setOnTouchListener(new View.OnTouchListener() {
//            public boolean onTouch(View view, MotionEvent motionEvent) {
//                switch (motionEvent.getAction()) {
//                    case MotionEvent.ACTION_DOWN:
//                        mFingerprintAnimator.setVisibility(View.GONE);
//                        mCircleView.setVisibility(View.VISIBLE);
//                        break;
//                    case MotionEvent.ACTION_UP:
//                    case MotionEvent.ACTION_CANCEL:
//						 mFingerprintAnimator.setVisibility(View.VISIBLE);
//						 mCircleView.setVisibility(View.GONE);
//                        break;
//                }
//                return true;
//            }
//        });
//    }@Overrideprotected BiometricEnrollSidecar getSidecar() {final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar();sidecar.setEnrollReason(FingerprintManager.ENROLL_ENROLL);return sidecar;}@Overrideprotected boolean shouldStartAutomatically() {if (mCanAssumeUdfps) {return mRestoring;}return true;}@Overrideprotected void onStart() {super.onStart();updateProgress(false);updateTitleAndDescription();if (mRestoring) {startIconAnimation();}}//    @Override
//    protected void onResume() {
//        super.onResume();
//        mGoodixFingerprintManager.showSensorViewWindow(true);
//        
//        mGoodixFingerprintManager.setHBMMode(true);
//    }@Overridepublic void onEnterAnimationComplete() {super.onEnterAnimationComplete();if (mCanAssumeUdfps) {startEnrollment();}mAnimationCancelled = false;startIconAnimation();}private void startIconAnimation() {if (mIconAnimationDrawable != null) {mIconAnimationDrawable.start();}}private void stopIconAnimation() {mAnimationCancelled = true;if (mIconAnimationDrawable != null) {mIconAnimationDrawable.stop();}}@Overrideprotected void onStop() {super.onStop();stopIconAnimation();//        mGoodixFingerprintManager.showSensorViewWindow(false);
//        mGoodixFingerprintManager.setHBMMode(false);}//    @Override
//    protected void onPause() {
//        super.onPause();
//        android.util.Log.d("zgyFp", "--onPause--");
//        mGoodixFingerprintManager.showSensorViewWindow(false);
//    }@Overrideprotected void onDestroy() {stopListenOrientationEvent();super.onDestroy();}private void animateProgress(int progress) {if (mCanAssumeUdfps) {if (progress >= PROGRESS_BAR_MAX) {getMainThreadHandler().postDelayed(mDelayedFinishRunnable, getFinishDelay());}return;}if (mProgressAnim != null) {mProgressAnim.cancel();}ObjectAnimator anim = ObjectAnimator.ofInt(mProgressBar, "progress", mProgressBar.getProgress(), progress);anim.addListener(mProgressAnimationListener);anim.setInterpolator(mFastOutSlowInInterpolator);anim.setDuration(250);anim.start();mProgressAnim = anim;}private void animateFlash() {if (mIconBackgroundBlinksDrawable != null) {mIconBackgroundBlinksDrawable.start();}}protected Intent getFinishIntent() {return new Intent(this, FingerprintEnrollFinish.class);}private void updateTitleAndDescription() {if (mCanAssumeUdfps) {updateTitleAndDescriptionForUdfps();return;}if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {setDescriptionText(R.string.security_settings_fingerprint_enroll_start_message);} else {setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_message);}}private void updateTitleAndDescriptionForUdfps() {switch (getCurrentStage()) {case STAGE_CENTER:setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);setDescriptionText(R.string.security_settings_udfps_enroll_start_message);break;case STAGE_GUIDED:setHeaderText(R.string.security_settings_fingerprint_enroll_repeat_title);if (mIsAccessibilityEnabled) {setDescriptionText(R.string.security_settings_udfps_enroll_repeat_a11y_message);} else {setDescriptionText(R.string.security_settings_udfps_enroll_repeat_message);}break;case STAGE_FINGERTIP:setHeaderText(R.string.security_settings_udfps_enroll_fingertip_title);if (!mHaveShownUdfpsTipLottie && mIllustrationLottie != null) {mHaveShownUdfpsTipLottie = true;setDescriptionText("");mIllustrationLottie.setAnimation(R.raw.udfps_tip_hint_lottie);mIllustrationLottie.setVisibility(View.VISIBLE);mIllustrationLottie.playAnimation();mIllustrationLottie.setContentDescription(getString(R.string.security_settings_udfps_tip_fingerprint_help));}break;case STAGE_LEFT_EDGE:setHeaderText(R.string.security_settings_udfps_enroll_left_edge_title);if (!mHaveShownUdfpsLeftEdgeLottie && mIllustrationLottie != null) {mHaveShownUdfpsLeftEdgeLottie = true;setDescriptionText("");mIllustrationLottie.setAnimation(R.raw.udfps_left_edge_hint_lottie);mIllustrationLottie.setVisibility(View.VISIBLE);mIllustrationLottie.playAnimation();mIllustrationLottie.setContentDescription(getString(R.string.security_settings_udfps_side_fingerprint_help));} else if (mIllustrationLottie == null) {if (isStageHalfCompleted()) {setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_message);} else {setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);}}break;case STAGE_RIGHT_EDGE:setHeaderText(R.string.security_settings_udfps_enroll_right_edge_title);if (!mHaveShownUdfpsRightEdgeLottie && mIllustrationLottie != null) {mHaveShownUdfpsRightEdgeLottie = true;setDescriptionText("");mIllustrationLottie.setAnimation(R.raw.udfps_right_edge_hint_lottie);mIllustrationLottie.setVisibility(View.VISIBLE);mIllustrationLottie.playAnimation();mIllustrationLottie.setContentDescription(getString(R.string.security_settings_udfps_side_fingerprint_help));} else if (mIllustrationLottie == null) {if (isStageHalfCompleted()) {setDescriptionText(R.string.security_settings_fingerprint_enroll_repeat_message);} else {setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);}}break;case STAGE_UNKNOWN:default:getLayout().setHeaderText(R.string.security_settings_fingerprint_enroll_udfps_title);setDescriptionText(R.string.security_settings_udfps_enroll_start_message);final CharSequence description = getString(R.string.security_settings_udfps_enroll_a11y);getLayout().getHeaderTextView().setContentDescription(description);setTitle(description);break;}}@EnrollStageprivate int getCurrentStage() {if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {return STAGE_UNKNOWN;}final int progressSteps = mSidecar.getEnrollmentSteps() - mSidecar.getEnrollmentRemaining();if (progressSteps < getStageThresholdSteps(0)) {return STAGE_CENTER;} else if (progressSteps < getStageThresholdSteps(1)) {return STAGE_GUIDED;} else if (progressSteps < getStageThresholdSteps(2)) {return STAGE_FINGERTIP;} else if (progressSteps < getStageThresholdSteps(3)) {return STAGE_LEFT_EDGE;} else {return STAGE_RIGHT_EDGE;}}private boolean isStageHalfCompleted() {if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {return false;}final int progressSteps = mSidecar.getEnrollmentSteps() - mSidecar.getEnrollmentRemaining();int prevThresholdSteps = 0;for (int i = 0; i < mFingerprintManager.getEnrollStageCount(); i++) {final int thresholdSteps = getStageThresholdSteps(i);if (progressSteps >= prevThresholdSteps && progressSteps < thresholdSteps) {final int adjustedProgress = progressSteps - prevThresholdSteps;final int adjustedThreshold = thresholdSteps - prevThresholdSteps;return adjustedProgress >= adjustedThreshold / 2;}prevThresholdSteps = thresholdSteps;}return true;}private int getStageThresholdSteps(int index) {if (mSidecar == null || mSidecar.getEnrollmentSteps() == -1) {Log.w(TAG, "getStageThresholdSteps: Enrollment not started yet");return 1;}return Math.round(mSidecar.getEnrollmentSteps() * mFingerprintManager.getEnrollStageThreshold(index));}@Overridepublic void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {if (!TextUtils.isEmpty(helpString)) {if (!mCanAssumeUdfps) {mErrorText.removeCallbacks(mTouchAgainRunnable);}showError(helpString);}}@Overridepublic void onEnrollmentError(int errMsgId, CharSequence errString) {Log.d(TAG, "--onEnrollmentError--" + errString);FingerprintErrorDialog.showErrorDialog(this, errMsgId);stopIconAnimation();if (!mCanAssumeUdfps) {mErrorText.removeCallbacks(mTouchAgainRunnable);}}@Overridepublic void onEnrollmentProgressChange(int steps, int remaining) {Log.d(TAG, "----onEnrollmentProgressChange----"+steps + " , remaining = " + remaining);updateProgress(true);updateTitleAndDescription();clearError();animateFlash();if (!mCanAssumeUdfps) {mErrorText.removeCallbacks(mTouchAgainRunnable);mErrorText.postDelayed(mTouchAgainRunnable, HINT_TIMEOUT_DURATION);} else {if (mIsAccessibilityEnabled) {final int percent = (int) (((float)(steps - remaining) / (float) steps) * 100);CharSequence cs = getString(R.string.security_settings_udfps_enroll_progress_a11y_message, percent);AccessibilityEvent e = AccessibilityEvent.obtain();e.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);e.setClassName(getClass().getName());e.setPackageName(getPackageName());e.getText().add(cs);mAccessibilityManager.sendAccessibilityEvent(e);}}}private void updateProgress(boolean animate) {if (mSidecar == null || !mSidecar.isEnrolling()) {Log.d(TAG, "Enrollment not started yet");return;}int progress = getProgress(mSidecar.getEnrollmentSteps(), mSidecar.getEnrollmentRemaining());Log.d(TAG, "--updateProgress--" + progress);
//        if (animate) {animateProgress(progress);
//        } else {if (mProgressBar != null) {mProgressBar.setProgress(progress);}if (progress >= PROGRESS_BAR_MAX) {mDelayedFinishRunnable.run();}
//        }}private int getProgress(int steps, int remaining) {if (steps == -1) {return 0;}int progress = Math.max(0, steps + 1 - remaining);return PROGRESS_BAR_MAX * progress / (steps + 1);}private void showError(CharSequence error) {if (mCanAssumeUdfps) {setHeaderText(error);setDescriptionText("");} else {mErrorText.setText(error);if (mErrorText.getVisibility() == View.INVISIBLE) {mErrorText.setVisibility(View.VISIBLE);mErrorText.setTranslationY(getResources().getDimensionPixelSize(R.dimen.fingerprint_error_text_appear_distance));mErrorText.setAlpha(0f);mErrorText.animate().alpha(1f).translationY(0f).setDuration(200).setInterpolator(mLinearOutSlowInInterpolator).start();} else {mErrorText.animate().cancel();mErrorText.setAlpha(1f);mErrorText.setTranslationY(0f);}}if (isResumed() && mIsAccessibilityEnabled && !mCanAssumeUdfps) {mVibrator.vibrate(Process.myUid(), getApplicationContext().getOpPackageName(),VIBRATE_EFFECT_ERROR, getClass().getSimpleName() + "::showError",FINGERPRINT_ENROLLING_SONFICATION_ATTRIBUTES);}}private void clearError() {if (!mCanAssumeUdfps && mErrorText.getVisibility() == View.VISIBLE) {mErrorText.animate().alpha(0f).translationY(getResources().getDimensionPixelSize(R.dimen.fingerprint_error_text_disappear_distance)).setDuration(100).setInterpolator(mFastOutLinearInInterpolator).withEndAction(() -> mErrorText.setVisibility(View.INVISIBLE)).start();}}private void listenOrientationEvent() {mOrientationEventListener = new OrientationEventListener(this) {@Overridepublic void onOrientationChanged(int orientation) {final int currentRotation = getDisplay().getRotation();if ((mPreviousRotation == Surface.ROTATION_90 && currentRotation == Surface.ROTATION_270) || (mPreviousRotation == Surface.ROTATION_270 && currentRotation == Surface.ROTATION_90)) {mPreviousRotation = currentRotation;recreate();}}};mOrientationEventListener.enable();mPreviousRotation = getDisplay().getRotation();}private void stopListenOrientationEvent() {if (mOrientationEventListener != null) {mOrientationEventListener.disable();}mOrientationEventListener = null;}private final Animator.AnimatorListener mProgressAnimationListener = new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) { }@Overridepublic void onAnimationRepeat(Animator animation) { }@Overridepublic void onAnimationEnd(Animator animation) {if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {mProgressBar.postDelayed(mDelayedFinishRunnable, getFinishDelay());}}@Overridepublic void onAnimationCancel(Animator animation) { }};private long getFinishDelay() {return mCanAssumeUdfps ? 400L : 250L;}private final Runnable mDelayedFinishRunnable = new Runnable() {@Overridepublic void run() {launchFinish(mToken);}};//    private final Runnable mDelayedSendCmd = new Runnable() {
//        @Override
//        public void run() {
//        	 Log.d(TAG, "--mDelayedSendCmd--" );
//        	 mGoodixFingerprintManager.testCmd(ShenzhenConstants.CMD_TEST_SZ_FINGER_DOWN);
//        }
//    };private final Animatable2.AnimationCallback mIconAnimationCallback = new Animatable2.AnimationCallback() {@Overridepublic void onAnimationEnd(Drawable d) {if (mAnimationCancelled) {return;}mProgressBar.post(new Runnable() {@Overridepublic void run() {startIconAnimation();}});}};private final Runnable mTouchAgainRunnable = new Runnable() {@Overridepublic void run() {showError(getString(R.string.security_settings_fingerprint_enroll_lift_touch_again));}};@Overridepublic int getMetricsCategory() {return SettingsEnums.FINGERPRINT_ENROLLING;}private void updateOrientation(int orientation) {switch(orientation) {case Configuration.ORIENTATION_LANDSCAPE: {mIllustrationLottie = null;break;}case Configuration.ORIENTATION_PORTRAIT: {if (mShouldShowLottie) {mIllustrationLottie = findViewById(R.id.illustration_lottie);}break;}}}@Overridepublic void onConfigurationChanged(@NonNull Configuration newConfig) {switch(newConfig.orientation) {case Configuration.ORIENTATION_LANDSCAPE: {updateOrientation(Configuration.ORIENTATION_LANDSCAPE);break;}case Configuration.ORIENTATION_PORTRAIT: {updateOrientation(Configuration.ORIENTATION_PORTRAIT);break;}}}
}

基本上不用怎么修改。

3, 最重要的是在System UI 里, 下面详细的介绍。

首先在SystemUI里加入汇顶的 库 GoodixFingerprintManager , 在bp文件里添加

vendor/mediatek/proprietary/packages/apps/SystemUI/Android.bp// add yk
android_library_import {name: "mtkgf_manager_lib",aars: ["libs/gf_manager_lib.aar"],
}
// end

AndroidManifest.xml 里要修改下, 不然编译会报错,replace标签里添加label , vendor/mediatek/proprietary/packages/apps/SystemUI/AndroidManifest.xml

 tools:replace="android:label,android:appComponentFactory"

编译成功后,在 vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/biometrics/AuthController.java 初始化 GoodixFingerprintManager 

 mGoodixFingerprintManager = GoodixFingerprintManager.getFingerprintManager(mContext); // add 

 mGoodixFingerprint.showSensorViewWindow(true); 显示汇顶的指纹解锁的窗口

  mGoodixFingerprint.setHBMMode(true); 显示高亮

汇顶的人员建议不要调用他们的来实现, 为此, 我就反编译他们的做了一个,反编译的代码后面贴出。

vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java 这个是核心类,

这个类里主要作用是工厂方法模式实现显示录指纹,解锁等不同的UI ,

    fun inflateUdfpsAnimation(view: UdfpsView, controller: UdfpsController): UdfpsAnimationViewController<*>? {return when (requestReason) {REASON_ENROLL_FIND_SENSOR,REASON_ENROLL_ENROLLING -> {Log.i("zgyFp", " REASON_ENROLL_ENROLLING  ")null/*  UdfpsEnrollViewController(view.addUdfpsView(R.layout.udfps_enroll_view) {},enrollHelper ?: throw IllegalStateException("no enrollment helper"),statusBarStateController,panelExpansionStateManager,dialogManager,dumpManager,overlayParams.scaleFactor) */}BiometricOverlayConstants.REASON_AUTH_KEYGUARD -> {Log.i("zgyFp", " REASON_AUTH_KEYGUARD  ")UdfpsKeyguardViewController(view.addUdfpsView(R.layout.udfps_keyguard_view),statusBarStateController, panelExpansionStateManager,statusBarKeyguardViewManager, keyguardUpdateMonitor, dumpManager, transitionController,configurationController, systemClock, keyguardStateController, unlockedScreenOffAnimationController,dialogManager, controller, activityLaunchAnimator)}BiometricOverlayConstants.REASON_AUTH_BP -> {UdfpsBpViewController(view.addUdfpsView(R.layout.udfps_bp_view), statusBarStateController, panelExpansionStateManager, dialogManager, dumpManager)}BiometricOverlayConstants.REASON_AUTH_OTHER,BiometricOverlayConstants.REASON_AUTH_SETTINGS -> {UdfpsFpmOtherViewController(view.addUdfpsView(R.layout.udfps_fpm_other_view), statusBarStateController, panelExpansionStateManager, dialogManager, dumpManager)}else -> {Log.e(TAG, "Animation for reason $requestReason not supported yet")null}}}

完成后的解锁视频

完成后的视频

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/809473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

架构设计-订单系统之业务的设计与实现

一、背景简介 订单业务一直都是系统研发中的核心模块&#xff0c;订单的产生过程&#xff0c;与系统中的很多模块都会高度关联&#xff0c;比如账户体系、支付中心、运营管理等&#xff0c;即便单看订单本身&#xff0c;也足够的复杂&#xff1b; 业务在发展的过程中&#xff…

Go gorm库(详细版)

目录 01. 什么是ORM 02. 环境搭建 03. 连接数据库 高级设置 gorm 的命名策略 创建表 日志显示 04. 模型定义 定义一张表 自动生成表结构 修改表字段大小 字段标签 05. 单表查询 5.1 表结构 5.2 添加单条记录 5.3 批量插入 5.4 单条数据查询 5.5 根据主键查询…

Vue3学习03 pinia

Vue3学习 pinia pinia一个简单效果搭建 pinia 环境存储读取数据示例 修改数据 (三种方式)storeToRefsgetters$subscribestore组合式写法 pinia 在vue2中使用vuex&#xff0c;在vue3中使用pinia。 集中式状态管理&#xff0c;&#xff08;状态数据&#xff09;。多个组件共享数…

多态【C/C++复习版】

目录 一、多态是什么&#xff1f;如何实现&#xff1f; 二、 什么是重写&#xff1f;有什么特点&#xff1f; 三、什么是协变&#xff1f; 四、析构函数能实现多态吗&#xff1f;为什么要实现&#xff1f; 五、override和final的作用是什么&#xff1f; 六、 多态的原理是…

Linux下网络编程基础知识--协议

网络基础 这一个课程的笔记 相关文章 协议 Socket编程 高并发服务器实现 线程池 协议 一组规则, 数据传输和数据的解释的规则。 比如说依次发送文件的文件名, 文件的大小, 以及实际的文件, 这样规定发送一个文件的顺序以及发送的每一个部分的格式等可以算是一种协议 型协议 …

防火墙用户管理技术——AAA

目录 一.AAA功能 (1).认证方式 (2).授权方式 (3).计费方式 二.RADUIUS协议 三.用户组织架构及管理 管理员认证登录方式 1.console 2.web 3.telnet 4.ssh 5.ftp 四.认证方式 五.AAA远程登录 1.端口添加IP地址达到互通 2.AAA视图进行配置 3.结果​编辑 一.AAA功能…

Android源码解析之截屏事件流程

今天这篇文章我们主要讲一下Android系统中的截屏事件处理流程。用过android系统手机的同学应该都知道&#xff0c;一般的android手机按下音量减少键和电源按键就会触发截屏事件&#xff08;国内定制机做个修改的这里就不做考虑了&#xff09;。那么这里的截屏事件是如何触发的呢…

【Redis深度解析】揭秘Cluster(集群):原理、机制与实战优化

Redis Cluster是Redis官方提供的分布式解决方案&#xff0c;通过数据分片与节点间通信机制&#xff0c;实现了水平扩展、高可用与数据容灾。本文将深入剖析Redis Cluster的工作原理、核心机制&#xff0c;并结合实战经验分享优化策略&#xff0c;为您打造坚实可靠的Redis分布式…

双数据库的安装

双MySQL的安装 【0】前言 ​ 本地已经安装过mysql5.1版本&#xff0c;应项目需求需要安装mysql5.7版本&#xff1b; ​ 官方网站下载对应版本&#xff1a;https://downloads.mysql.com/archives/community/ 【1】压缩包下载完成后解压至本地磁盘 【2】进入根目录下bin文件夹…

Flask基于flask_login实现登录、验证码

flask_login 是一个 Flask 扩展&#xff0c;用于在 Flask web 应用中实现用户会话管理。它允许你跟踪哪些用户已经登录&#xff0c;并管理他们的登录状态。flask_login 提供了用户认证的基础结构&#xff0c;但具体的用户验证&#xff08;如用户名和密码检查&#xff09;和存储…

泽众Testone自动化测试平台,测试用例支持单个调试执行,同步查看执行日志

泽众Testone自动化测试平台之前版本&#xff0c;测试用例批量和单个执行&#xff0c;必须要通过测试集操作执行&#xff0c;操作略繁琐&#xff0c;我们通过本轮优化升级&#xff0c;测试用例直接可以单个调试执行&#xff0c;同步查看执行日志&#xff0c;操作上去繁就简&…

OJ刷题日记:1、双指针(1)

目录 1、283.移动零 2、1089.复写零 3、202.快乐数 1、283.移动零 题目&#xff1a; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 …

第十届 蓝桥杯 单片机设计与开发项目 省赛

第十届 蓝桥杯 单片机设计与开发项目 省赛 输入&#xff1a; 频率信号输入模拟电压输入 输出&#xff08;包含各种显示功能&#xff09;&#xff1a; LED显示SEG显示DAC输出 01 数码管显示问题&#xff1a;数据类型 bit Seg_Disp_Mode;//0-频率显示界面 1-电压显示界面 un…

电脑无法开机?原因分析与解决方案

电脑无法开机是一种常见的问题&#xff0c;可能会给用户带来诸多困扰。无法启动可能是由于硬件故障、软件问题或者其他未知原因引起的。在本文中&#xff0c;我们将介绍三种常见的方法来解决电脑无法开机的问题&#xff0c;以帮助用户尽快恢复正常使用。 方法1&#xff1a;检查…

什么是队列

队列是一种特殊类型的线性表&#xff0c;其只允许在一端进行插入操作&#xff0c;而在另一端进行删除操作。具体来说&#xff0c;允许插入的一端称为队尾&#xff0c;而允许删除的一端称为队头。这种数据结构遵循“先进先出”&#xff08;FIFO&#xff09;的原则&#xff0c;即…

ubuntu安装irtualbox注意事项

下载官网7.0版本&#xff0c;ubuntu22.04,安装一直出错误&#xff0c;查到了下面兄弟的办法&#xff0c;仍然不幸&#xff0c;最后使用apt重装&#xff0c;请按第二部分流程安装&#xff0c;安装6.1,可以用 第一部分&#xff0c;反正我是没搞通&#xff0c;7.0反复的出现相同的…

C语言读取 .ico 文件并显示数据

原来是想做光标编辑器&#xff0c;自己把绘图板的内容导出为光标格式 鼠标指针文件格式解析——Windows&#xff08;一&#xff09; (qq.com) 代码来源自 Icons | Microsoft Learn 鄙人又补充些变量可以运行微软的代码 简单代码如下 #include <stdio.h> #include &l…

神经网络模型底层原理与实现8-BERT

首先介绍什么是自监督学习&#xff1a; 普通的有监督学习是每个x对应有个y&#xff0c;x训练得到y&#xff0c;将y与y作比较&#xff0c;而自监督是没有对应y&#xff0c;直接把一部分样本x作为训练目标x&#xff0c;训练得x后和x对比 bert中如何创造x&#xff1a;以文字处理为…

4/11 QT_day5

服务器端 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QMessageBox> #include <QTcpSocket> #include <QList> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass …

MSTP/RSTP与STP的兼容性

原理概述 MSTP(Multiple STP)协议和RSTP(Rapid STP)协议都可以向下兼容STP&#xff08;Spanning Tree Protocol &#xff09;协议。运行MSTP/RSTP协议的交换机会根据收到的BPDU版本号信息自动判断与之相连的交换机的运行模式。如果收到的是STP BPDU&#xff0c;MSTP/RSTP交换机…