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