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

java 复制代码
final int[] udfpsProps = getContext().getResources().getIntArray(com.android.internal.R.array.config_udfps_sensor_props);

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

XML 复制代码
    <!-- 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

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

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;

    @Override
    protected 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;
//            }
//        });
//    }
    
    @Override
    protected BiometricEnrollSidecar getSidecar() {
        final FingerprintEnrollSidecar sidecar = new FingerprintEnrollSidecar();
        sidecar.setEnrollReason(FingerprintManager.ENROLL_ENROLL);
        return sidecar;
    }

    @Override
    protected boolean shouldStartAutomatically() {
        if (mCanAssumeUdfps) {
            return mRestoring;
        }
        return true;
    }

    @Override
    protected void onStart() {
        super.onStart();
        updateProgress(false);
        updateTitleAndDescription();
        if (mRestoring) {
            startIconAnimation();
        }
    }
    
//    @Override
//    protected void onResume() {
//        super.onResume();
//        mGoodixFingerprintManager.showSensorViewWindow(true);
//        
//        mGoodixFingerprintManager.setHBMMode(true);
//    }
    
    @Override
    public 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();
        }
    }

    @Override
    protected 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);
//    }

    @Override
    protected 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;
        }
    }

    @EnrollStage
    private 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));
    }

    @Override
    public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
        if (!TextUtils.isEmpty(helpString)) {
            if (!mCanAssumeUdfps) {
                mErrorText.removeCallbacks(mTouchAgainRunnable);
            }
            showError(helpString);
        }
    }

    @Override
    public void onEnrollmentError(int errMsgId, CharSequence errString) {
    	Log.d(TAG, "--onEnrollmentError--" + errString);
        FingerprintErrorDialog.showErrorDialog(this, errMsgId);
        stopIconAnimation();
        if (!mCanAssumeUdfps) {
            mErrorText.removeCallbacks(mTouchAgainRunnable);
        }
    }

    @Override
    public 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) {
            @Override
            public 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() {
                @Override
                public void onAnimationStart(Animator animation) { }
                @Override
                public void onAnimationRepeat(Animator animation) { }
                @Override
                public void onAnimationEnd(Animator animation) {
                    if (mProgressBar.getProgress() >= PROGRESS_BAR_MAX) {
                        mProgressBar.postDelayed(mDelayedFinishRunnable, getFinishDelay());
                    }
                }
                @Override
                public void onAnimationCancel(Animator animation) { }
            };

    private long getFinishDelay() {
        return mCanAssumeUdfps ? 400L : 250L;
    }

    private final Runnable mDelayedFinishRunnable = new Runnable() {
        @Override
        public 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() {
        @Override
        public void onAnimationEnd(Drawable d) {
            if (mAnimationCancelled) {
                return;
            }

            mProgressBar.post(new Runnable() {
                @Override
                public void run() {
                    startIconAnimation();
                }
            });
        }
    };

    private final Runnable mTouchAgainRunnable = new Runnable() {
        @Override
        public void run() {
            showError(getString(R.string.security_settings_fingerprint_enroll_lift_touch_again));
        }
    };

    @Override
    public 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;
            }
        }
    }

    @Override
    public 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文件里添加

java 复制代码
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

java 复制代码
 tools:replace="android:label,android:appComponentFactory"

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

java 复制代码
 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 ,

Kotlin 复制代码
    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
            }
        }
    }

完成后的解锁视频

完成后的视频

相关推荐
太空漫步112 小时前
android社畜模拟器
android
海绵宝宝_4 小时前
【HarmonyOS NEXT】获取正式应用签名证书的签名信息
android·前端·华为·harmonyos·鸿蒙·鸿蒙应用开发
凯文的内存6 小时前
android 定制mtp连接外设的设备名称
android·media·mtp·mtpserver
天若子6 小时前
Android今日头条的屏幕适配方案
android
林的快手8 小时前
伪类选择器
android·前端·css·chrome·ajax·html·json
望佑8 小时前
Tmp detached view should be removed from RecyclerView before it can be recycled
android
xvch10 小时前
Kotlin 2.1.0 入门教程(二十四)泛型、泛型约束、绝对非空类型、下划线运算符
android·kotlin
人民的石头14 小时前
Android系统开发 给system/app传包报错
android
yujunlong391914 小时前
android,flutter 混合开发,通信,传参
android·flutter·混合开发·enginegroup
rkmhr_sef14 小时前
万字详解 MySQL MGR 高可用集群搭建
android·mysql·adb