• 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 android.annotation.Nullable;
20 import android.app.Activity;
21 import android.app.Fragment;
22 import android.app.KeyguardManager;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.Intent;
25 import android.content.IntentSender;
26 import android.os.Bundle;
27 import android.os.UserManager;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.internal.widget.LockPatternUtils;
31 import com.android.settings.SettingsActivity;
32 import com.android.settings.Utils;
33 import com.android.setupwizardlib.util.WizardManagerHelper;
34 
35 public final class ChooseLockSettingsHelper {
36 
37     public static final String EXTRA_KEY_TYPE = "type";
38     public static final String EXTRA_KEY_PASSWORD = "password";
39     public static final String EXTRA_KEY_RETURN_CREDENTIALS = "return_credentials";
40     public static final String EXTRA_KEY_HAS_CHALLENGE = "has_challenge";
41     public static final String EXTRA_KEY_CHALLENGE = "challenge";
42     public static final String EXTRA_KEY_CHALLENGE_TOKEN = "hw_auth_token";
43     public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint";
44     public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot";
45 
46     /**
47      * When invoked via {@link ConfirmLockPassword.InternalActivity}, this flag
48      * controls if we relax the enforcement of
49      * {@link Utils#enforceSameOwner(android.content.Context, int)}.
50      */
51     public static final String EXTRA_ALLOW_ANY_USER = "allow_any_user";
52 
53     @VisibleForTesting LockPatternUtils mLockPatternUtils;
54     private Activity mActivity;
55     private Fragment mFragment;
56 
ChooseLockSettingsHelper(Activity activity)57     public ChooseLockSettingsHelper(Activity activity) {
58         mActivity = activity;
59         mLockPatternUtils = new LockPatternUtils(activity);
60     }
61 
ChooseLockSettingsHelper(Activity activity, Fragment fragment)62     public ChooseLockSettingsHelper(Activity activity, Fragment fragment) {
63         this(activity);
64         mFragment = fragment;
65     }
66 
utils()67     public LockPatternUtils utils() {
68         return mLockPatternUtils;
69     }
70 
71     /**
72      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
73      *
74      * @param title title of the confirmation screen; shown in the action bar
75      * @return true if one exists and we launched an activity to confirm it
76      * @see Activity#onActivityResult(int, int, android.content.Intent)
77      */
launchConfirmationActivity(int request, CharSequence title)78     public boolean launchConfirmationActivity(int request, CharSequence title) {
79         return launchConfirmationActivity(request, title, null, null, false, false);
80     }
81 
82     /**
83      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
84      *
85      * @param title title of the confirmation screen; shown in the action bar
86      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
87      *                          this can only be called internally.
88      * @return true if one exists and we launched an activity to confirm it
89      * @see Activity#onActivityResult(int, int, android.content.Intent)
90      */
launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials)91     public boolean launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials) {
92         return launchConfirmationActivity(request, title, null, null, returnCredentials, false);
93     }
94 
95     /**
96      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
97      *
98      * @param title title of the confirmation screen; shown in the action bar
99      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
100      *                          this can only be called internally.
101      * @param userId The userId for whom the lock should be confirmed.
102      * @return true if one exists and we launched an activity to confirm it
103      * @see Activity#onActivityResult(int, int, android.content.Intent)
104      */
launchConfirmationActivity(int request, CharSequence title, boolean returnCredentials, int userId)105     public boolean launchConfirmationActivity(int request, CharSequence title,
106             boolean returnCredentials, int userId) {
107         return launchConfirmationActivity(request, title, null, null,
108                 returnCredentials, false, false, 0, Utils.enforceSameOwner(mActivity, userId));
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 header header of the confirmation screen; shown as large text
116      * @param description description of the confirmation screen
117      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
118      *                          this can only be called internally.
119      * @param external specifies whether this activity is launched externally, meaning that it will
120      *                 get a dark theme, allow fingerprint authentication and it will forward
121      *                 activity result.
122      * @return true if one exists and we launched an activity to confirm it
123      * @see Activity#onActivityResult(int, int, android.content.Intent)
124      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external)125     boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
126             @Nullable CharSequence header, @Nullable CharSequence description,
127             boolean returnCredentials, boolean external) {
128         return launchConfirmationActivity(request, title, header, description,
129                 returnCredentials, external, false, 0, Utils.getCredentialOwnerUserId(mActivity));
130     }
131 
132     /**
133      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
134      *
135      * @param title title of the confirmation screen; shown in the action bar
136      * @param header header of the confirmation screen; shown as large text
137      * @param description description of the confirmation screen
138      * @param returnCredentials if true, put credentials into intent. Note that if this is true,
139      *                          this can only be called internally.
140      * @param external specifies whether this activity is launched externally, meaning that it will
141      *                 get a dark theme, allow fingerprint authentication and it will forward
142      *                 activity result.
143      * @param userId The userId for whom the lock should be confirmed.
144      * @return true if one exists and we launched an activity to confirm it
145      * @see Activity#onActivityResult(int, int, android.content.Intent)
146      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, int userId)147     boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
148             @Nullable CharSequence header, @Nullable CharSequence description,
149             boolean returnCredentials, boolean external, int userId) {
150         return launchConfirmationActivity(request, title, header, description,
151                 returnCredentials, external, false, 0, Utils.enforceSameOwner(mActivity, 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 challenge a challenge to be verified against the device credential.
161      * @return true if one exists and we launched an activity to confirm it
162      * @see Activity#onActivityResult(int, int, android.content.Intent)
163      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, long challenge)164     public boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
165             @Nullable CharSequence header, @Nullable CharSequence description,
166             long challenge) {
167         return launchConfirmationActivity(request, title, header, description,
168                 true, false, true, challenge, Utils.getCredentialOwnerUserId(mActivity));
169     }
170 
171     /**
172      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
173      *
174      * @param title title of the confirmation screen; shown in the action bar
175      * @param header header of the confirmation screen; shown as large text
176      * @param description description of the confirmation screen
177      * @param challenge a challenge to be verified against the device credential.
178      * @param userId The userId for whom the lock should be confirmed.
179      * @return true if one exists and we launched an activity to confirm it
180      * @see Activity#onActivityResult(int, int, android.content.Intent)
181      */
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, long challenge, int userId)182     public boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
183             @Nullable CharSequence header, @Nullable CharSequence description,
184             long challenge, int userId) {
185         return launchConfirmationActivity(request, title, header, description,
186                 true, false, true, challenge, Utils.enforceSameOwner(mActivity, userId));
187     }
188 
189     /**
190      * If a pattern, password or PIN exists, prompt the user before allowing them to change it.
191      *
192      * @param title title of the confirmation screen; shown in the action bar
193      * @param header header of the confirmation screen; shown as large text
194      * @param description description of the confirmation screen
195      * @param external specifies whether this activity is launched externally, meaning that it will
196      *                 get a dark theme, allow fingerprint authentication and it will forward
197      *                 activity result.
198      * @param challenge a challenge to be verified against the device credential.
199      * @param userId The userId for whom the lock should be confirmed.
200      * @return true if one exists and we launched an activity to confirm it
201      * @see Activity#onActivityResult(int, int, android.content.Intent)
202      */
launchConfirmationActivityWithExternalAndChallenge(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean external, long challenge, int userId)203     public boolean launchConfirmationActivityWithExternalAndChallenge(int request,
204             @Nullable CharSequence title, @Nullable CharSequence header,
205             @Nullable CharSequence description, boolean external, long challenge, int userId) {
206         return launchConfirmationActivity(request, title, header, description, false,
207                 external, true, challenge, Utils.enforceSameOwner(mActivity, userId));
208     }
209 
210     /**
211      * Variant that allows you to prompt for credentials of any user, including
212      * those which aren't associated with the current user. As an example, this
213      * is useful when unlocking the storage for secondary users.
214      */
launchConfirmationActivityForAnyUser(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, int userId)215     public boolean launchConfirmationActivityForAnyUser(int request,
216             @Nullable CharSequence title, @Nullable CharSequence header,
217             @Nullable CharSequence description, int userId) {
218         final Bundle extras = new Bundle();
219         extras.putBoolean(EXTRA_ALLOW_ANY_USER, true);
220         return launchConfirmationActivity(request, title, header, description, false,
221                 false, true, 0, userId, extras);
222     }
223 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId)224     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
225             @Nullable CharSequence header, @Nullable CharSequence description,
226             boolean returnCredentials, boolean external, boolean hasChallenge,
227             long challenge, int userId) {
228         return launchConfirmationActivity(request, title, header, description, returnCredentials,
229                 external, hasChallenge, challenge, userId, null /* alternateButton */, null);
230     }
231 
launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, int userId, Bundle extras)232     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
233             @Nullable CharSequence header, @Nullable CharSequence description,
234             boolean returnCredentials, boolean external, boolean hasChallenge,
235             long challenge, int userId, Bundle extras) {
236         return launchConfirmationActivity(request, title, header, description, returnCredentials,
237                 external, hasChallenge, challenge, userId, null /* alternateButton */, extras);
238     }
239 
launchFrpConfirmationActivity(int request, @Nullable CharSequence header, @Nullable CharSequence description, @Nullable CharSequence alternateButton)240     public boolean launchFrpConfirmationActivity(int request, @Nullable CharSequence header,
241             @Nullable CharSequence description, @Nullable CharSequence alternateButton) {
242         return launchConfirmationActivity(request, null /* title */, header, description,
243                 false /* returnCredentials */, true /* external */, false /* hasChallenge */,
244                 0 /* challenge */, LockPatternUtils.USER_FRP, alternateButton, null);
245     }
246 
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)247     private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
248             @Nullable CharSequence header, @Nullable CharSequence description,
249             boolean returnCredentials, boolean external, boolean hasChallenge,
250             long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras) {
251         final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
252         boolean launched = false;
253 
254         switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) {
255             case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
256                 launched = launchConfirmationActivity(request, title, header, description,
257                         returnCredentials || hasChallenge
258                                 ? ConfirmLockPattern.InternalActivity.class
259                                 : ConfirmLockPattern.class, returnCredentials, external,
260                                 hasChallenge, challenge, userId, alternateButton, extras);
261                 break;
262             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
263             case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
264             case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
265             case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
266             case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
267             case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
268                 launched = launchConfirmationActivity(request, title, header, description,
269                         returnCredentials || hasChallenge
270                                 ? ConfirmLockPassword.InternalActivity.class
271                                 : ConfirmLockPassword.class, returnCredentials, external,
272                                 hasChallenge, challenge, userId, alternateButton, extras);
273                 break;
274         }
275         return launched;
276     }
277 
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)278     private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header,
279             CharSequence message, Class<?> activityClass, boolean returnCredentials,
280             boolean external, boolean hasChallenge, long challenge,
281             int userId, @Nullable CharSequence alternateButton, Bundle extras) {
282         final Intent intent = new Intent();
283         intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title);
284         intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header);
285         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT, message);
286         intent.putExtra(ConfirmDeviceCredentialBaseFragment.ALLOW_FP_AUTHENTICATION, external);
287         // TODO: Remove dark theme and show_cancel_button options since they are no longer used
288         intent.putExtra(ConfirmDeviceCredentialBaseFragment.DARK_THEME, false);
289         intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_CANCEL_BUTTON, false);
290         intent.putExtra(ConfirmDeviceCredentialBaseFragment.SHOW_WHEN_LOCKED, external);
291         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, returnCredentials);
292         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, hasChallenge);
293         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
294         // we should never have a drawer when confirming device credentials.
295         intent.putExtra(SettingsActivity.EXTRA_HIDE_DRAWER, true);
296         intent.putExtra(Intent.EXTRA_USER_ID, userId);
297         intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton);
298         if (extras != null) {
299             intent.putExtras(extras);
300         }
301         intent.setClassName(ConfirmDeviceCredentialBaseFragment.PACKAGE, activityClass.getName());
302         if (external) {
303             intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
304             if (mFragment != null) {
305                 copyOptionalExtras(mFragment.getActivity().getIntent(), intent);
306                 mFragment.startActivity(intent);
307             } else {
308                 copyOptionalExtras(mActivity.getIntent(), intent);
309                 mActivity.startActivity(intent);
310             }
311         } else {
312             if (mFragment != null) {
313                 copyInternalExtras(mFragment.getActivity().getIntent(), intent);
314                 mFragment.startActivityForResult(intent, request);
315             } else {
316                 copyInternalExtras(mActivity.getIntent(), intent);
317                 mActivity.startActivityForResult(intent, request);
318             }
319         }
320         return true;
321     }
322 
copyOptionalExtras(Intent inIntent, Intent outIntent)323     private void copyOptionalExtras(Intent inIntent, Intent outIntent) {
324         IntentSender intentSender = inIntent.getParcelableExtra(Intent.EXTRA_INTENT);
325         if (intentSender != null) {
326             outIntent.putExtra(Intent.EXTRA_INTENT, intentSender);
327         }
328         int taskId = inIntent.getIntExtra(Intent.EXTRA_TASK_ID, -1);
329         if (taskId != -1) {
330             outIntent.putExtra(Intent.EXTRA_TASK_ID, taskId);
331         }
332         // If we will launch another activity once credentials are confirmed, exclude from recents.
333         // This is a workaround to a framework bug where affinity is incorrect for activities
334         // that are started from a no display activity, as is ConfirmDeviceCredentialActivity.
335         // TODO: Remove once that bug is fixed.
336         if (intentSender != null || taskId != -1) {
337             outIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
338             outIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
339         }
340     }
341 
copyInternalExtras(Intent inIntent, Intent outIntent)342     private void copyInternalExtras(Intent inIntent, Intent outIntent) {
343         String theme = inIntent.getStringExtra(WizardManagerHelper.EXTRA_THEME);
344         if (theme != null) {
345             outIntent.putExtra(WizardManagerHelper.EXTRA_THEME, theme);
346         }
347     }
348 }
349