1 package com.android.internal.widget;
2 
3 import android.os.AsyncTask;
4 
5 import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
6 
7 import java.util.ArrayList;
8 import java.util.List;
9 
10 /**
11  * Helper class to check/verify PIN/Password/Pattern asynchronously.
12  */
13 public 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          */
onEarlyMatched()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          */
onChecked(boolean matched, int throttleTimeoutMs)32         void onChecked(boolean matched, int throttleTimeoutMs);
33 
34         /**
35          * Called when the underlying AsyncTask was cancelled.
36          */
onCancelled()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          */
onVerified(byte[] attestation, int throttleTimeoutMs)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      */
verifyPattern(final LockPatternUtils utils, final List<LockPatternView.Cell> pattern, final long challenge, final int userId, final OnVerifyCallback callback)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      */
checkPattern(final LockPatternUtils utils, final List<LockPatternView.Cell> pattern, final int userId, final OnCheckCallback callback)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      */
verifyPassword(final LockPatternUtils utils, final String password, final long challenge, final int userId, final OnVerifyCallback callback)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      */
verifyTiedProfileChallenge(final LockPatternUtils utils, final String password, final boolean isPattern, final long challenge, final int userId, final OnVerifyCallback callback)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      */
checkPassword(final LockPatternUtils utils, final String password, final int userId, final OnCheckCallback callback)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