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         * Called when the underlying AsyncTask was cancelled.
36         */
37        default void onCancelled() {}
38    }
39
40    /**
41     * Interface for a callback to be invoked after security verification.
42     */
43    public interface OnVerifyCallback {
44        /**
45         * Invoked when a security verification is finished.
46         *
47         * @param attestation The attestation that the challenge was verified, or null.
48         * @param throttleTimeoutMs The amount of time in ms to wait before reattempting
49         * the call. Only non-0 if attestation is null.
50         */
51        void onVerified(byte[] attestation, int throttleTimeoutMs);
52    }
53
54    /**
55     * Verify a pattern asynchronously.
56     *
57     * @param utils The LockPatternUtils instance to use.
58     * @param pattern The pattern to check.
59     * @param challenge The challenge to verify against the pattern.
60     * @param userId The user to check against the pattern.
61     * @param callback The callback to be invoked with the verification result.
62     */
63    public static AsyncTask<?, ?, ?> verifyPattern(final LockPatternUtils utils,
64            final List<LockPatternView.Cell> pattern,
65            final long challenge,
66            final int userId,
67            final OnVerifyCallback callback) {
68        AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
69            private int mThrottleTimeout;
70            private List<LockPatternView.Cell> patternCopy;
71
72            @Override
73            protected void onPreExecute() {
74                // Make a copy of the pattern to prevent race conditions.
75                // No need to clone the individual cells because they are immutable.
76                patternCopy = new ArrayList(pattern);
77            }
78
79            @Override
80            protected byte[] doInBackground(Void... args) {
81                try {
82                    return utils.verifyPattern(patternCopy, challenge, userId);
83                } catch (RequestThrottledException ex) {
84                    mThrottleTimeout = ex.getTimeoutMs();
85                    return null;
86                }
87            }
88
89            @Override
90            protected void onPostExecute(byte[] result) {
91                callback.onVerified(result, mThrottleTimeout);
92            }
93        };
94        task.execute();
95        return task;
96    }
97
98    /**
99     * Checks a pattern asynchronously.
100     *
101     * @param utils The LockPatternUtils instance to use.
102     * @param pattern The pattern to check.
103     * @param userId The user to check against the pattern.
104     * @param callback The callback to be invoked with the check result.
105     */
106    public static AsyncTask<?, ?, ?> checkPattern(final LockPatternUtils utils,
107            final List<LockPatternView.Cell> pattern,
108            final int userId,
109            final OnCheckCallback callback) {
110        AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
111            private int mThrottleTimeout;
112            private List<LockPatternView.Cell> patternCopy;
113
114            @Override
115            protected void onPreExecute() {
116                // Make a copy of the pattern to prevent race conditions.
117                // No need to clone the individual cells because they are immutable.
118                patternCopy = new ArrayList(pattern);
119            }
120
121            @Override
122            protected Boolean doInBackground(Void... args) {
123                try {
124                    return utils.checkPattern(patternCopy, userId, callback::onEarlyMatched);
125                } catch (RequestThrottledException ex) {
126                    mThrottleTimeout = ex.getTimeoutMs();
127                    return false;
128                }
129            }
130
131            @Override
132            protected void onPostExecute(Boolean result) {
133                callback.onChecked(result, mThrottleTimeout);
134            }
135
136            @Override
137            protected void onCancelled() {
138                callback.onCancelled();
139            }
140        };
141        task.execute();
142        return task;
143    }
144
145    /**
146     * Verify a password asynchronously.
147     *
148     * @param utils The LockPatternUtils instance to use.
149     * @param password The password to check.
150     * @param challenge The challenge to verify against the pattern.
151     * @param userId The user to check against the pattern.
152     * @param callback The callback to be invoked with the verification result.
153     */
154    public static AsyncTask<?, ?, ?> verifyPassword(final LockPatternUtils utils,
155            final String password,
156            final long challenge,
157            final int userId,
158            final OnVerifyCallback callback) {
159        AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
160            private int mThrottleTimeout;
161
162            @Override
163            protected byte[] doInBackground(Void... args) {
164                try {
165                    return utils.verifyPassword(password, challenge, userId);
166                } catch (RequestThrottledException ex) {
167                    mThrottleTimeout = ex.getTimeoutMs();
168                    return null;
169                }
170            }
171
172            @Override
173            protected void onPostExecute(byte[] result) {
174                callback.onVerified(result, mThrottleTimeout);
175            }
176        };
177        task.execute();
178        return task;
179    }
180
181    /**
182     * Verify a password asynchronously.
183     *
184     * @param utils The LockPatternUtils instance to use.
185     * @param password The password to check.
186     * @param challenge The challenge to verify against the pattern.
187     * @param userId The user to check against the pattern.
188     * @param callback The callback to be invoked with the verification result.
189     */
190    public static AsyncTask<?, ?, ?> verifyTiedProfileChallenge(final LockPatternUtils utils,
191            final String password,
192            final boolean isPattern,
193            final long challenge,
194            final int userId,
195            final OnVerifyCallback callback) {
196        AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
197            private int mThrottleTimeout;
198
199            @Override
200            protected byte[] doInBackground(Void... args) {
201                try {
202                    return utils.verifyTiedProfileChallenge(password, isPattern, challenge, userId);
203                } catch (RequestThrottledException ex) {
204                    mThrottleTimeout = ex.getTimeoutMs();
205                    return null;
206                }
207            }
208
209            @Override
210            protected void onPostExecute(byte[] result) {
211                callback.onVerified(result, mThrottleTimeout);
212            }
213        };
214        task.execute();
215        return task;
216    }
217
218    /**
219     * Checks a password asynchronously.
220     *
221     * @param utils The LockPatternUtils instance to use.
222     * @param password The password to check.
223     * @param userId The user to check against the pattern.
224     * @param callback The callback to be invoked with the check result.
225     */
226    public static AsyncTask<?, ?, ?> checkPassword(final LockPatternUtils utils,
227            final String password,
228            final int userId,
229            final OnCheckCallback callback) {
230        AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
231            private int mThrottleTimeout;
232
233            @Override
234            protected Boolean doInBackground(Void... args) {
235                try {
236                    return utils.checkPassword(password, userId, callback::onEarlyMatched);
237                } catch (RequestThrottledException ex) {
238                    mThrottleTimeout = ex.getTimeoutMs();
239                    return false;
240                }
241            }
242
243            @Override
244            protected void onPostExecute(Boolean result) {
245                callback.onChecked(result, mThrottleTimeout);
246            }
247
248            @Override
249            protected void onCancelled() {
250                callback.onCancelled();
251            }
252        };
253        task.execute();
254        return task;
255    }
256}
257