• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.password;
18 
19 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
20 
21 import android.annotation.Nullable;
22 import android.app.Activity;
23 import android.app.KeyguardManager;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.Intent;
26 import android.content.IntentSender;
27 import android.os.Bundle;
28 import android.os.UserManager;
29 
30 import androidx.annotation.VisibleForTesting;
31 import androidx.fragment.app.Fragment;
32 
33 import com.android.internal.widget.LockPatternUtils;
34 import com.android.settings.SetupWizardUtils;
35 import com.android.settings.Utils;
36 
37 import com.google.android.setupcompat.util.WizardManagerHelper;
38 
39 public final class ChooseLockSettingsHelper {
40 
41     public static final String EXTRA_KEY_TYPE = "type";
42     public static final String EXTRA_KEY_PASSWORD = "password";
43     public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials";
44     public static final String EXTRA_KEY_HAS_CHALLENGE = "has_challenge";
45     public static final String EXTRA_KEY_CHALLENGE = "challenge";
46     public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token";
47     public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint";
48     public static final String EXTRA_KEY_FOR_FACE = "for_face";
49     public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
50 
51     /**
52      * Intent extra for passing the requested min password complexity to later steps in the set new
53      * screen lock flow.
54      */
55     public static final String EXTRA_KEY_REQUESTED_MIN_COMPLEXITY = "requested_min_complexity";
56 
57     /**
58      * Intent extra for passing the label of the calling app to later steps in the set new screen
59      * lock flow.
60      */
61     public static final String EXTRA_KEY_CALLER_APP_NAME = "caller_app_name";
62 
63     /**
64      * Intent extra indicating that the calling app is an admin, such as a Device Adimn, Device
65      * Owner, or Profile Owner.
66      */
67     public static final String EXTRA_KEY_IS_CALLING_APP_ADMIN = "is_calling_app_admin";
68 
69     /**
70      * When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
71      * controls if we relax the enforcement of
72      * {@link Utils#enforceSameOwner(android.content.Context, int)}.
73      */
74     public static final String EXTRA_ALLOW_ANY_USER = "allow_any_user";
75 
76     @VisibleForTesting LockPatternUtils mLockPatternUtils;
77     private Activity mActivity;
78     private Fragment mFragment;
79 
ChooseLockSettingsHelper(Activity activity)80     public ChooseLockSettingsHelper(Activity activity) {
81         mActivity = activity;
82         mLockPatternUtils = new LockPatternUtils(activity);
83     }
84 
ChooseLockSettingsHelper(Activity activity, Fragment fragment)85     public ChooseLockSettingsHelper(Activity activity, Fragment fragment) {
86         this(activity);
87         mFragment = fragment;
88     }
89 
utils()90     public LockPatternUtils utils() {
91         return mLockPatternUtils;
92     }
93 
94     /**
95      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
96      *
97      * @param title title of the confirmation screen; shown in the action bar
98      * @return true if one exists and we launched an activity to confirm it
99      * @see Activity#onActivityResult(int, int, android.content.Intent)
100      */
launchConfirmationActivity(int request, CharSequence title)101     public boolean launchConfirmationActivity(int request, CharSequence title) {
102         return launchConfirmationActivity(
103                 request /* request */,
104                 title /* title */,
105                 null /* header */,
106                 null /* description */,
107                 false /* returnCredentials */,
108                 false /* external */);
109     }
110 
111     /**
112      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
113      *
114      * @param title title of the confirmation screen; shown in the action bar
115      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
116      *                          this can only be called internally.
117      * @return true if one exists and we launched an activity to confirm it
118      * @see Activity#onActivityResult(int, int, android.content.Intent)
119      */
launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials)120     public boolean launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials) {
121         return launchConfirmationActivity(
122                 request /* request */,
123                 title /* title */,
124                 null /* header */,
125                 null /* description */,
126                 returnCredentials /* returnCredentials */,
127                 false /* external */);
128     }
129 
130     /**
131      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
132      *
133      * @param title title of the confirmation screen; shown in the action bar
134      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
135      *                          this can only be called internally.
136      * @param userId The userId for whom the lock should be confirmed.
137      * @return true if one exists and we launched an activity to confirm it
138      * @see Activity#onActivityResult(int, int, android.content.Intent)
139      */
launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials, int userId)140     public boolean launchConfirmationActivity(int request, CharSequence title,
141             boolean returnCredentials, int userId) {
142         return launchConfirmationActivity(
143                 request /* request */,
144                 title /* title */,
145                 null /* header */,
146                 null /* description */,
147                 returnCredentials /* returnCredentials */,
148                 false /* external */,
149                 false /* hasChallenge */,
150                 0 /* challenge */,
151                 Utils.enforceSameOwner(mActivity, userId) /* userId */);
152     }
153 
154     /**
155      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
156      *
157      * @param title title of the confirmation screen; shown in the action bar
158      * @param header header of the confirmation screen; shown as large text
159      * @param description description of the confirmation screen
160      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
161      *                          this can only be called internally.
162      * @param external specifies whether this activity is launched externally, meaning that it will
163      *                 get a dark theme, allow fingerprint authentication and it will forward
164      *                 activity result.
165      * @return true if one exists and we launched an activity to confirm it
166      * @see Activity#onActivityResult(int, int, android.content.Intent)
167      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external)168     boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
169             @Nullable CharSequence header, @Nullable CharSequence description,
170             boolean returnCredentials, boolean external) {
171         return launchConfirmationActivity(
172                 request /* request */,
173                 title /* title */,
174                 header /* header */,
175                 description /* description */,
176                 returnCredentials /* returnCredentials */,
177                 external /* external */,
178                 false /* hasChallenge */,
179                 0 /* challenge */,
180                 Utils.getCredentialOwnerUserId(mActivity) /* userId */);
181     }
182 
183     /**
184      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
185      *
186      * @param title title of the confirmation screen; shown in the action bar
187      * @param header header of the confirmation screen; shown as large text
188      * @param description description of the confirmation screen
189      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
190      *                          this can only be called internally.
191      * @param external specifies whether this activity is launched externally, meaning that it will
192      *                 get a dark theme, allow fingerprint authentication and it will forward
193      *                 activity result.
194      * @param userId The userId for whom the lock should be confirmed.
195      * @return true if one exists and we launched an activity to confirm it
196      * @see Activity#onActivityResult(int, int, android.content.Intent)
197      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, int userId)198     boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
199             @Nullable CharSequence header, @Nullable CharSequence description,
200             boolean returnCredentials, boolean external, int userId) {
201         return launchConfirmationActivity(
202                 request /* request */,
203                 title /* title */,
204                 header /* header */,
205                 description /* description */,
206                 returnCredentials /* returnCredentials */,
207                 external /* external */,
208                 false /* hasChallenge */,
209                 0 /* challenge */,
210                 Utils.enforceSameOwner(mActivity, userId) /* userId */);
211     }
212 
213     /**
214      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
215      *
216      * @param title title of the confirmation screen; shown in the action bar
217      * @param header header of the confirmation screen; shown as large text
218      * @param description description of the confirmation screen
219      * @param challenge a challenge to be verified against the device credential.
220      * @return true if one exists and we launched an activity to confirm it
221      * @see Activity#onActivityResult(int, int, android.content.Intent)
222      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, long challenge)223     public boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
224             @Nullable CharSequence header, @Nullable CharSequence description,
225             long challenge) {
226         return launchConfirmationActivity(
227                 request /* request */,
228                 title /* title */,
229                 header /* header */,
230                 description /* description */,
231                 true /* returnCredentials */,
232                 false /* external */,
233                 true /* hasChallenge */,
234                 challenge /* challenge */,
235                 Utils.getCredentialOwnerUserId(mActivity) /* userId */);
236     }
237 
238     /**
239      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
240      *
241      * @param title title of the confirmation screen; shown in the action bar
242      * @param header header of the confirmation screen; shown as large text
243      * @param description description of the confirmation screen
244      * @param challenge a challenge to be verified against the device credential.
245      * @param userId The userId for whom the lock should be confirmed.
246      * @return true if one exists and we launched an activity to confirm it
247      * @see Activity#onActivityResult(int, int, android.content.Intent)
248      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, long challenge, int userId)249     public boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
250             @Nullable CharSequence header, @Nullable CharSequence description,
251             long challenge, int userId) {
252         return launchConfirmationActivity(
253                 request /* request */,
254                 title /* title */,
255                 header /* header */,
256                 description /* description */,
257                 true /* returnCredentials */,
258                 false /* external */,
259                 true /* hasChallenge */,
260                 challenge /* challenge */,
261                 Utils.enforceSameOwner(mActivity, userId) /* userId */);
262     }
263 
264     /**
265      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
266      *
267      * @param title title of the confirmation screen; shown in the action bar
268      * @param header header of the confirmation screen; shown as large text
269      * @param description description of the confirmation screen
270      * @param external specifies whether this activity is launched externally, meaning that it will
271      *                 get a dark theme, allow fingerprint authentication and it will forward
272      *                 activity result.
273      * @param challenge a challenge to be verified against the device credential.
274      * @param userId The userId for whom the lock should be confirmed.
275      * @return true if one exists and we launched an activity to confirm it
276      * @see Activity#onActivityResult(int, int, android.content.Intent)
277      */
launchConfirmationActivityWithExternalAndChallenge(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean external, long challenge, int userId)278     public boolean launchConfirmationActivityWithExternalAndChallenge(int request,
279             @Nullable CharSequence title, @Nullable CharSequence header,
280             @Nullable CharSequence description, boolean external, long challenge, int userId) {
281         return launchConfirmationActivity(
282                 request /* request */,
283                 title /* title */,
284                 header /* header */,
285                 description /* description */,
286                 false /* returnCredentials */,
287                 external /* external */,
288                 true /* hasChallenge */,
289                 challenge /* challenge */,
290                 Utils.enforceSameOwner(mActivity, userId) /* userId */);
291     }
292 
293     /**
294      * Variant that allows you to prompt for credentials of any user, including
295      * those which aren't associated with the current user. As an example, this
296      * is useful when unlocking the storage for secondary users.
297      */
launchConfirmationActivityForAnyUser(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, int userId)298     public boolean launchConfirmationActivityForAnyUser(int request,
299             @Nullable CharSequence title, @Nullable CharSequence header,
300             @Nullable CharSequence description, int userId) {
301         final Bundle extras = new Bundle();
302         extras.putBoolean(EXTRA_ALLOW_ANY_USER, true);
303         return launchConfirmationActivity(
304                 request /* request */,
305                 title /* title */,
306                 header /* header */,
307                 description /* description */,
308                 false /* returnCredentials */,
309                 false /* external */,
310                 true /* hasChallenge */,
311                 0 /* challenge */,
312                 userId /* userId */,
313                 extras /* extras */);
314     }
315 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId)316     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
317             @Nullable CharSequence header, @Nullable CharSequence description,
318             boolean returnCredentials, boolean external, boolean hasChallenge,
319             long challenge, int userId) {
320         return launchConfirmationActivity(
321                 request /* request */,
322                 title /* title */,
323                 header /* header */,
324                 description /* description */,
325                 returnCredentials /* returnCredentials */,
326                 external /* external */,
327                 hasChallenge /* hasChallenge */,
328                 challenge /* challenge */,
329                 userId /* userId */,
330                 null /* alternateButton */,
331                 null /* extras */);
332     }
333 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, Bundle extras)334     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
335             @Nullable CharSequence header, @Nullable CharSequence description,
336             boolean returnCredentials, boolean external, boolean hasChallenge,
337             long challenge, int userId, Bundle extras) {
338         return launchConfirmationActivity(
339                 request /* request */,
340                 title /* title */,
341                 header /* header */,
342                 description /* description */,
343                 returnCredentials /* returnCredentials */,
344                 external /* external */,
345                 hasChallenge /* hasChallenge */,
346                 challenge /* challenge */,
347                 userId /* userId */,
348                 null /* alternateButton */,
349                 extras /* extras */);
350     }
351 
launchFrpConfirmationActivity(int request, @Nullable CharSequence header, @Nullable CharSequence description, @Nullable CharSequence alternateButton)352     public boolean launchFrpConfirmationActivity(int request, @Nullable CharSequence header,
353             @Nullable CharSequence description, @Nullable CharSequence alternateButton) {
354         return launchConfirmationActivity(
355                 request /* request */,
356                 null /* title */,
357                 header /* header */,
358                 description /* description */,
359                 false /* returnCredentials */,
360                 true /* external */,
361                 false /* hasChallenge */,
362                 0 /* challenge */,
363                 LockPatternUtils.USER_FRP /* userId */,
364                 alternateButton /* alternateButton */,
365                 null /* extras */);
366     }
367 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras)368     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
369             @Nullable CharSequence header, @Nullable CharSequence description,
370             boolean returnCredentials, boolean external, boolean hasChallenge,
371             long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras) {
372         final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
373         boolean launched = false;
374 
375         switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) {
376             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
377                 launched = launchConfirmationActivity(request, title, header, description,
378                         returnCredentials || hasChallenge
379                                 ? ConfirmLockPattern.InternalActivity.class
380                                 : ConfirmLockPattern.class, returnCredentials, external,
381                                 hasChallenge, challenge, userId, alternateButton, extras);
382                 break;
383             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
384             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
385             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
386             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
387             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
388             case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
389                 launched = launchConfirmationActivity(request, title, header, description,
390                         returnCredentials || hasChallenge
391                                 ? ConfirmLockPassword.InternalActivity.class
392                                 : ConfirmLockPassword.class, returnCredentials, external,
393                                 hasChallenge, challenge, userId, alternateButton, extras);
394                 break;
395         }
396         return launched;
397     }
398 
launchConfirmationActivity(int request, CharSequence title, CharSequence header, CharSequence message, Class<?> activityClass, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras)399     private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header,
400             CharSequence message, Class<?> activityClass, boolean returnCredentials,
401             boolean external, boolean hasChallenge, long challenge,
402             int userId, @Nullable CharSequence alternateButton, Bundle extras) {
403         final Intent intent = new Intent();
404         intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
405         intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
406         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT, message);
407         // TODO: Remove dark theme and show_cancel_button options since they are no longer used
408         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, false);
409         intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false);
410         intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external);
411         intent.putExtra(ConfirmDeviceCredentialBaseFragment.USE_FADE_ANIMATION, external);
412         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, returnCredentials);
413         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, hasChallenge);
414         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
415         intent.putExtra(Intent.EXTRA_USER_ID, userId);
416         intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
417         if (extras != null) {
418             intent.putExtras(extras);
419         }
420         intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName());
421         if (external) {
422             intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
423             if (mFragment != null) {
424                 copyOptionalExtras(mFragment.getActivity().getIntent(), intent);
425                 mFragment.startActivity(intent);
426             } else {
427                 copyOptionalExtras(mActivity.getIntent(), intent);
428                 mActivity.startActivity(intent);
429             }
430         } else {
431             if (mFragment != null) {
432                 copyInternalExtras(mFragment.getActivity().getIntent(), intent);
433                 mFragment.startActivityForResult(intent, request);
434             } else {
435                 copyInternalExtras(mActivity.getIntent(), intent);
436                 mActivity.startActivityForResult(intent, request);
437             }
438         }
439         return true;
440     }
441 
copyOptionalExtras(Intent inIntent, Intent outIntent)442     private void copyOptionalExtras(Intent inIntent, Intent outIntent) {
443         IntentSender intentSender = inIntent.getParcelableExtra(Intent.EXTRA_INTENT);
444         if (intentSender != null) {
445             outIntent.putExtra(Intent.EXTRA_INTENT, intentSender);
446         }
447         int taskId = inIntent.getIntExtra(Intent.EXTRA_TASK_ID, -1);
448         if (taskId != -1) {
449             outIntent.putExtra(Intent.EXTRA_TASK_ID, taskId);
450         }
451         // If we will launch another activity once credentials are confirmed, exclude from recents.
452         // This is a workaround to a framework bug where affinity is incorrect for activities
453         // that are started from a no display activity, as is ConfirmDeviceCredentialActivity.
454         // TODO: Remove once that bug is fixed.
455         if (intentSender != null || taskId != -1) {
456             outIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
457             outIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
458         }
459     }
460 
copyInternalExtras(Intent inIntent, Intent outIntent)461     private void copyInternalExtras(Intent inIntent, Intent outIntent) {
462         SetupWizardUtils.copySetupExtras(inIntent, outIntent);
463         String theme = inIntent.getStringExtra(WizardManagerHelper.EXTRA_THEME);
464         if (theme != null) {
465             outIntent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
466         }
467     }
468 }
469