1package com.android.internal.widget;
2
3import android.os.AsyncTask;
4
5import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
6
7import java.util.ArrayList;
8import java.util.List;
9
10/**
11 * Helper class to check/verify PIN/Password/Pattern asynchronously.
12 */
13public final class LockPatternChecker {
14    /**
15     * Interface for a callback to be invoked after security check.
16     */
17    public interface OnCheckCallback {
18
19        /**
20         * Invoked as soon as possible we know that the credentials match. This will be called
21         * earlier than {@link #onChecked} but only if the credentials match.
22         */
23        default void onEarlyMatched() {}
24
25        /**
26         * Invoked when a security check is finished.
27         *
28         * @param matched Whether the PIN/Password/Pattern matches the stored one.
29         * @param throttleTimeoutMs The amount of time in ms to wait before reattempting
30         * the call. Only non-0 if matched is false.
31         */
32        void onChecked(boolean matched, int throttleTimeoutMs);
33    }
34
35    /**
36     * Interface for a callback to be invoked after security verification.
37     */
38    public interface OnVerifyCallback {
39        /**
40         * Invoked when a security verification is finished.
41         *
42         * @param attestation The attestation that the challenge was verified, or null.
43         * @param throttleTimeoutMs The amount of time in ms to wait before reattempting
44         * the call. Only non-0 if attestation is null.
45         */
46        void onVerified(byte[] attestation, int throttleTimeoutMs);
47    }
48
49    /**
50     * Verify a pattern asynchronously.
51     *
52     * @param utils The LockPatternUtils instance to use.
53     * @param pattern The pattern to check.
54     * @param challenge The challenge to verify against the pattern.
55     * @param userId The user to check against the pattern.
56     * @param callback The callback to be invoked with the verification result.
57     */
58    public static AsyncTask<?, ?, ?> verifyPattern(final LockPatternUtils utils,
59            final List<LockPatternView.Cell> pattern,
60            final long challenge,
61            final int userId,
62            final OnVerifyCallback callback) {
63        AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
64            private int mThrottleTimeout;
65            private List<LockPatternView.Cell> patternCopy;
66
67            @Override
68            protected void onPreExecute() {
69                // Make a copy of the pattern to prevent race conditions.
70                // No need to clone the individual cells because they are immutable.
71                patternCopy = new ArrayList(pattern);
72            }
73
74            @Override
75            protected byte[] doInBackground(Void... args) {
76                try {
77                    return utils.verifyPattern(patternCopy, challenge, userId);
78                } catch (RequestThrottledException ex) {
79                    mThrottleTimeout = ex.getTimeoutMs();
80                    return null;
81                }
82            }
83
84            @Override
85            protected void onPostExecute(byte[] result) {
86                callback.onVerified(result, mThrottleTimeout);
87            }
88        };
89        task.execute();
90        return task;
91    }
92
93    /**
94     * Checks a pattern asynchronously.
95     *
96     * @param utils The LockPatternUtils instance to use.
97     * @param pattern The pattern to check.
98     * @param userId The user to check against the pattern.
99     * @param callback The callback to be invoked with the check result.
100     */
101    public static AsyncTask<?, ?, ?> checkPattern(final LockPatternUtils utils,
102            final List<LockPatternView.Cell> pattern,
103            final int userId,
104            final OnCheckCallback callback) {
105        AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
106            private int mThrottleTimeout;
107            private List<LockPatternView.Cell> patternCopy;
108
109            @Override
110            protected void onPreExecute() {
111                // Make a copy of the pattern to prevent race conditions.
112                // No need to clone the individual cells because they are immutable.
113                patternCopy = new ArrayList(pattern);
114            }
115
116            @Override
117            protected Boolean doInBackground(Void... args) {
118                try {
119                    return utils.checkPattern(patternCopy, userId, callback::onEarlyMatched);
120                } catch (RequestThrottledException ex) {
121                    mThrottleTimeout = ex.getTimeoutMs();
122                    return false;
123                }
124            }
125
126            @Override
127            protected void onPostExecute(Boolean result) {
128                callback.onChecked(result, mThrottleTimeout);
129            }
130        };
131        task.execute();
132        return task;
133    }
134
135    /**
136     * Verify a password asynchronously.
137     *
138     * @param utils The LockPatternUtils instance to use.
139     * @param password The password to check.
140     * @param challenge The challenge to verify against the pattern.
141     * @param userId The user to check against the pattern.
142     * @param callback The callback to be invoked with the verification result.
143     */
144    public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
145            final String password,
146            final long challenge,
147            final int userId,
148            final OnVerifyCallback callback) {
149        AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
150            private int mThrottleTimeout;
151
152            @Override
153            protected byte[] doInBackground(Void... args) {
154                try {
155                    return utils.verifyPassword(password, challenge, userId);
156                } catch (RequestThrottledException ex) {
157                    mThrottleTimeout = ex.getTimeoutMs();
158                    return null;
159                }
160            }
161
162            @Override
163            protected void onPostExecute(byte[] result) {
164                callback.onVerified(result, mThrottleTimeout);
165            }
166        };
167        task.execute();
168        return task;
169    }
170
171    /**
172     * Verify a password asynchronously.
173     *
174     * @param utils The LockPatternUtils instance to use.
175     * @param password The password to check.
176     * @param challenge The challenge to verify against the pattern.
177     * @param userId The user to check against the pattern.
178     * @param callback The callback to be invoked with the verification result.
179     */
180    public static AsyncTask<?, ?, ?> verifyTiedProfileChallenge(final LockPatternUtils utils,
181            final String password,
182            final boolean isPattern,
183            final long challenge,
184            final int userId,
185            final OnVerifyCallback callback) {
186        AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
187            private int mThrottleTimeout;
188
189            @Override
190            protected byte[] doInBackground(Void... args) {
191                try {
192                    return utils.verifyTiedProfileChallenge(password, isPattern, challenge, userId);
193                } catch (RequestThrottledException ex) {
194                    mThrottleTimeout = ex.getTimeoutMs();
195                    return null;
196                }
197            }
198
199            @Override
200            protected void onPostExecute(byte[] result) {
201                callback.onVerified(result, mThrottleTimeout);
202            }
203        };
204        task.execute();
205        return task;
206    }
207
208    /**
209     * Checks a password asynchronously.
210     *
211     * @param utils The LockPatternUtils instance to use.
212     * @param password The password to check.
213     * @param userId The user to check against the pattern.
214     * @param callback The callback to be invoked with the check result.
215     */
216    public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
217            final String password,
218            final int userId,
219            final OnCheckCallback callback) {
220        AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
221            private int mThrottleTimeout;
222
223            @Override
224            protected Boolean doInBackground(Void... args) {
225                try {
226                    return utils.checkPassword(password, userId, callback::onEarlyMatched);
227                } catch (RequestThrottledException ex) {
228                    mThrottleTimeout = ex.getTimeoutMs();
229                    return false;
230                }
231            }
232
233            @Override
234            protected void onPostExecute(Boolean result) {
235                callback.onChecked(result, mThrottleTimeout);
236            }
237        };
238        task.execute();
239        return task;
240    }
241}
242