10f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi/*
20f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * Copyright (C) 2015 The Android Open Source Project
30f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi *
40f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
50f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * you may not use this file except in compliance with the License.
60f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * You may obtain a copy of the License at
70f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi *
80f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
90f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi *
100f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * Unless required by applicable law or agreed to in writing, software
110f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
120f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * See the License for the specific language governing permissions and
140f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * limitations under the License
150f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi */
160f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
170f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggipackage android.support.v4.hardware.fingerprint;
180f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
190f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggiimport android.content.Context;
200f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggiimport android.os.Build;
21febf93acf968f1722d3644f356b346987941fd94Jim Millerimport android.os.Handler;
220f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggiimport android.support.annotation.NonNull;
230f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggiimport android.support.annotation.Nullable;
24c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viveretteimport android.support.annotation.RequiresApi;
250f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggiimport android.support.v4.os.CancellationSignal;
260f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
270f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggiimport java.security.Signature;
280f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
290f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggiimport javax.crypto.Cipher;
30e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggiimport javax.crypto.Mac;
310f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
320f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi/**
330f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * A class that coordinates access to the fingerprint hardware.
340f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi * <p>
353d7a7c44f6781f8fe5960317959d21e3973aa01aDianne Hackborn * On platforms before {@link android.os.Build.VERSION_CODES#M}, this class behaves as there would
363d7a7c44f6781f8fe5960317959d21e3973aa01aDianne Hackborn * be no fingerprint hardware available.
370f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi */
38c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banespublic final class FingerprintManagerCompat {
390f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
400f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    private Context mContext;
410f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
420f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    /** Get a {@link FingerprintManagerCompat} instance for a provided context. */
430f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    public static FingerprintManagerCompat from(Context context) {
440f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        return new FingerprintManagerCompat(context);
450f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
460f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
470f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    private FingerprintManagerCompat(Context context) {
480f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        mContext = context;
490f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
500f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
510f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    static final FingerprintManagerCompatImpl IMPL;
520f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    static {
53c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette        if (Build.VERSION.SDK_INT >= 23) {
540f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            IMPL = new Api23FingerprintManagerCompatImpl();
550f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        } else {
560f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            IMPL = new LegacyFingerprintManagerCompatImpl();
570f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
580f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
590f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
600f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    /**
610f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * Determine if there is at least one fingerprint enrolled.
620f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     *
630f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * @return true if at least one fingerprint is enrolled, false otherwise
640f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     */
650f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    public boolean hasEnrolledFingerprints() {
660f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        return IMPL.hasEnrolledFingerprints(mContext);
670f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
680f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
690f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    /**
700f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * Determine if fingerprint hardware is present and functional.
710f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     *
720f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * @return true if hardware is present and functional, false otherwise.
730f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     */
740f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    public boolean isHardwareDetected() {
750f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        return IMPL.isHardwareDetected(mContext);
760f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
770f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
780f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    /**
790f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * Request authentication of a crypto object. This call warms up the fingerprint hardware
800f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * and starts scanning for a fingerprint. It terminates when
810f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
82377357a8c26c8c54ba8cb876ae775265635a8448Elliot Waite     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
830f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * which point the object is no longer valid. The operation can be canceled by using the
840f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * provided cancel object.
850f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     *
860f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * @param crypto object associated with the call or null if none required.
87febf93acf968f1722d3644f356b346987941fd94Jim Miller     * @param flags optional flags; should be 0
880f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * @param cancel an object that can be used to cancel authentication
890f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * @param callback an object to receive authentication events
90febf93acf968f1722d3644f356b346987941fd94Jim Miller     * @param handler an optional handler for events
910f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     */
92febf93acf968f1722d3644f356b346987941fd94Jim Miller    public void authenticate(@Nullable CryptoObject crypto, int flags,
930f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback,
94febf93acf968f1722d3644f356b346987941fd94Jim Miller            @Nullable Handler handler) {
95febf93acf968f1722d3644f356b346987941fd94Jim Miller        IMPL.authenticate(mContext, crypto, flags, cancel, callback, handler);
960f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
970f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
980f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    /**
990f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
1000f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * framework supports {@link Signature} and {@link Cipher} objects.
1010f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     */
1020f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    public static class CryptoObject {
1030f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1040f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        private final Signature mSignature;
1050f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        private final Cipher mCipher;
106e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi        private final Mac mMac;
1070f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1080f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public CryptoObject(Signature signature) {
1090f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            mSignature = signature;
1100f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            mCipher = null;
111e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            mMac = null;
112e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi
1130f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
1140f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1150f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public CryptoObject(Cipher cipher) {
1160f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            mCipher = cipher;
1170f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            mSignature = null;
118e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            mMac = null;
119e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi        }
120e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi
121e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi        public CryptoObject(Mac mac) {
122e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            mMac = mac;
123e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            mCipher = null;
124e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            mSignature = null;
1250f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
1260f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1270f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        /**
1280f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * Get {@link Signature} object.
1290f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @return {@link Signature} object or null if this doesn't contain one.
1300f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         */
1310f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public Signature getSignature() { return mSignature; }
1320f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1330f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        /**
1340f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * Get {@link Cipher} object.
1350f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @return {@link Cipher} object or null if this doesn't contain one.
1360f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         */
1370f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public Cipher getCipher() { return mCipher; }
138e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi
139e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi        /**
140e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi         * Get {@link Mac} object.
141e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi         * @return {@link Mac} object or null if this doesn't contain one.
142e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi         */
143e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi        public Mac getMac() { return mMac; }
1440f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
1450f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1460f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    /**
1470f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * Container for callback data from {@link FingerprintManagerCompat#authenticate(CryptoObject,
148febf93acf968f1722d3644f356b346987941fd94Jim Miller     *     int, CancellationSignal, AuthenticationCallback, Handler)}.
1490f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     */
1500f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    public static final class AuthenticationResult {
1510f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        private CryptoObject mCryptoObject;
1520f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1530f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public AuthenticationResult(CryptoObject crypto) {
1540f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            mCryptoObject = crypto;
1550f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
1560f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1570f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        /**
1580f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * Obtain the crypto object associated with this transaction
1590f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @return crypto object provided to {@link FingerprintManagerCompat#authenticate(
160febf93acf968f1722d3644f356b346987941fd94Jim Miller         *         CryptoObject, int, CancellationSignal, AuthenticationCallback, Handler)}.
1610f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         */
1620f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public CryptoObject getCryptoObject() { return mCryptoObject; }
1630f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
1640f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1650f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    /**
1660f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * Callback structure provided to {@link FingerprintManagerCompat#authenticate(CryptoObject,
167febf93acf968f1722d3644f356b346987941fd94Jim Miller     * int, CancellationSignal, AuthenticationCallback, Handler)}. Users of {@link
168febf93acf968f1722d3644f356b346987941fd94Jim Miller     * FingerprintManagerCompat#authenticate(CryptoObject, int, CancellationSignal,
169febf93acf968f1722d3644f356b346987941fd94Jim Miller     * AuthenticationCallback, Handler) } must provide an implementation of this for listening to
1700f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     * fingerprint events.
1710f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi     */
1720f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    public static abstract class AuthenticationCallback {
1730f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        /**
1740f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * Called when an unrecoverable error has been encountered and the operation is complete.
1750f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * No further callbacks will be made on this object.
1760f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @param errMsgId An integer identifying the error message
1770f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @param errString A human-readable error string that can be shown in UI
1780f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         */
1790f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public void onAuthenticationError(int errMsgId, CharSequence errString) { }
1800f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1810f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        /**
1820f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * Called when a recoverable error has been encountered during authentication. The help
1830f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * string is provided to give the user guidance for what went wrong, such as
1840f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * "Sensor dirty, please clean it."
1850f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @param helpMsgId An integer identifying the error message
1860f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @param helpString A human-readable string that can be shown in UI
1870f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         */
1880f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { }
1890f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1900f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        /**
1910f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * Called when a fingerprint is recognized.
1920f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * @param result An object containing authentication-related data
1930f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         */
1940f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public void onAuthenticationSucceeded(AuthenticationResult result) { }
1950f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
1960f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        /**
1970f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         * Called when a fingerprint is valid but not recognized.
1980f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi         */
1990f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public void onAuthenticationFailed() { }
2000f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
2010f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2020f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    private interface FingerprintManagerCompatImpl {
2030f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        boolean hasEnrolledFingerprints(Context context);
2040f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        boolean isHardwareDetected(Context context);
205febf93acf968f1722d3644f356b346987941fd94Jim Miller        void authenticate(Context context, CryptoObject crypto, int flags,
206febf93acf968f1722d3644f356b346987941fd94Jim Miller                CancellationSignal cancel, AuthenticationCallback callback, Handler handler);
2070f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
2080f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2090f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    private static class LegacyFingerprintManagerCompatImpl
2100f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            implements FingerprintManagerCompatImpl {
2110f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2120f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public LegacyFingerprintManagerCompatImpl() {
2130f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2140f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2150f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        @Override
2160f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public boolean hasEnrolledFingerprints(Context context) {
2170f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            return false;
2180f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2190f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2200f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        @Override
2210f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public boolean isHardwareDetected(Context context) {
2220f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            return false;
2230f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2240f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2250f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        @Override
226febf93acf968f1722d3644f356b346987941fd94Jim Miller        public void authenticate(Context context, CryptoObject crypto, int flags,
227febf93acf968f1722d3644f356b346987941fd94Jim Miller                CancellationSignal cancel, AuthenticationCallback callback, Handler handler) {
2280f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            // TODO: Figure out behavior when there is no fingerprint hardware available
2290f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2300f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
2310f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
232c69882cb9b130902c1554ef5d3e3b06d776cd796Alan Viverette    @RequiresApi(23)
2330f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    private static class Api23FingerprintManagerCompatImpl implements FingerprintManagerCompatImpl {
2340f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2350f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public Api23FingerprintManagerCompatImpl() {
2360f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2370f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2380f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        @Override
2390f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public boolean hasEnrolledFingerprints(Context context) {
2400f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            return FingerprintManagerCompatApi23.hasEnrolledFingerprints(context);
2410f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2420f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2430f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        @Override
2440f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        public boolean isHardwareDetected(Context context) {
2450f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            return FingerprintManagerCompatApi23.isHardwareDetected(context);
2460f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2470f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2480f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        @Override
249febf93acf968f1722d3644f356b346987941fd94Jim Miller        public void authenticate(Context context, CryptoObject crypto, int flags,
250febf93acf968f1722d3644f356b346987941fd94Jim Miller                CancellationSignal cancel, AuthenticationCallback callback, Handler handler) {
251febf93acf968f1722d3644f356b346987941fd94Jim Miller            FingerprintManagerCompatApi23.authenticate(context, wrapCryptoObject(crypto), flags,
2520f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                    cancel != null ? cancel.getCancellationSignalObject() : null,
253febf93acf968f1722d3644f356b346987941fd94Jim Miller                    wrapCallback(callback), handler);
2540f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2550f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2560f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        private static FingerprintManagerCompatApi23.CryptoObject wrapCryptoObject(
2570f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                CryptoObject cryptoObject) {
25850931369bc45988cfb44760dc3b52012bef56d3aJorim Jaggi            if (cryptoObject == null) {
25950931369bc45988cfb44760dc3b52012bef56d3aJorim Jaggi                return null;
26050931369bc45988cfb44760dc3b52012bef56d3aJorim Jaggi            } else if (cryptoObject.getCipher() != null) {
2610f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                return new FingerprintManagerCompatApi23.CryptoObject(cryptoObject.getCipher());
262e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            } else if (cryptoObject.getSignature() != null) {
2630f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                return new FingerprintManagerCompatApi23.CryptoObject(cryptoObject.getSignature());
264e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            } else if (cryptoObject.getMac() != null) {
265e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi                return new FingerprintManagerCompatApi23.CryptoObject(cryptoObject.getMac());
266e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            } else {
267e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi                return null;
2680f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            }
2690f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2700f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
271552766fa685c63ad760c92239faaba12e6ad51f1Aurimas Liutikas        static CryptoObject unwrapCryptoObject(
2720f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                FingerprintManagerCompatApi23.CryptoObject cryptoObject) {
27350931369bc45988cfb44760dc3b52012bef56d3aJorim Jaggi            if (cryptoObject == null) {
27450931369bc45988cfb44760dc3b52012bef56d3aJorim Jaggi                return null;
27550931369bc45988cfb44760dc3b52012bef56d3aJorim Jaggi            } else if (cryptoObject.getCipher() != null) {
2760f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                return new CryptoObject(cryptoObject.getCipher());
277e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            } else if (cryptoObject.getSignature() != null) {
2780f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                return new CryptoObject(cryptoObject.getSignature());
279e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            } else if (cryptoObject.getMac() != null) {
280e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi                return new CryptoObject(cryptoObject.getMac());
281e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi            } else {
282e70c5387272b23eb09b7324e88b8c5d8e4481b3fJorim Jaggi                return null;
2830f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            }
2840f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
2850f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2860f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        private static FingerprintManagerCompatApi23.AuthenticationCallback wrapCallback(
2870f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                final AuthenticationCallback callback) {
2880f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            return new FingerprintManagerCompatApi23.AuthenticationCallback() {
2890f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                @Override
2900f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                public void onAuthenticationError(int errMsgId, CharSequence errString) {
2910f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                    callback.onAuthenticationError(errMsgId, errString);
2920f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                }
2930f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2940f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                @Override
2950f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
2960f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                    callback.onAuthenticationHelp(helpMsgId, helpString);
2970f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                }
2980f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
2990f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                @Override
3000f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                public void onAuthenticationSucceeded(
3010f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                        FingerprintManagerCompatApi23.AuthenticationResultInternal result) {
3020f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                    callback.onAuthenticationSucceeded(new AuthenticationResult(
3030f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                            unwrapCryptoObject(result.getCryptoObject())));
3040f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                }
3050f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi
3060f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                @Override
3070f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                public void onAuthenticationFailed() {
3080f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                    callback.onAuthenticationFailed();
3090f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi                }
3100f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi            };
3110f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi        }
3120f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi    }
3130f46e110e9edcc92812670b3f4b918a84499265bJorim Jaggi}
314