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