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