• 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 android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PASSWORD_HEADER;
20 import static android.app.admin.DevicePolicyResources.Strings.Settings.CONFIRM_WORK_PROFILE_PIN_HEADER;
21 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE;
22 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE;
23 import static android.app.admin.DevicePolicyResources.UNDEFINED;
24 
25 import static com.android.settings.biometrics.GatekeeperPasswordProvider.containsGatekeeperPasswordHandle;
26 import static com.android.settings.biometrics.GatekeeperPasswordProvider.getGatekeeperPasswordHandle;
27 import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE;
28 
29 import android.app.KeyguardManager;
30 import android.app.RemoteLockscreenValidationResult;
31 import android.app.admin.DevicePolicyManager;
32 import android.app.settings.SettingsEnums;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.graphics.Typeface;
36 import android.os.AsyncTask;
37 import android.os.Bundle;
38 import android.os.CountDownTimer;
39 import android.os.Handler;
40 import android.os.Looper;
41 import android.os.SystemClock;
42 import android.os.UserHandle;
43 import android.os.UserManager;
44 import android.text.Editable;
45 import android.text.InputType;
46 import android.text.TextUtils;
47 import android.util.Log;
48 import android.view.KeyEvent;
49 import android.view.LayoutInflater;
50 import android.view.View;
51 import android.view.View.OnClickListener;
52 import android.view.ViewGroup;
53 import android.view.animation.AnimationUtils;
54 import android.view.inputmethod.EditorInfo;
55 import android.view.inputmethod.InputMethodManager;
56 import android.widget.ImeAwareEditText;
57 import android.widget.TextView;
58 import android.widget.TextView.OnEditorActionListener;
59 
60 import androidx.annotation.Nullable;
61 import androidx.fragment.app.Fragment;
62 
63 import com.android.internal.widget.LockPatternChecker;
64 import com.android.internal.widget.LockPatternUtils;
65 import com.android.internal.widget.LockscreenCredential;
66 import com.android.internal.widget.TextViewInputDisabler;
67 import com.android.settings.R;
68 import com.android.settings.SetupRedactionInterstitial;
69 import com.android.settings.Utils;
70 import com.android.settingslib.animation.AppearAnimationUtils;
71 import com.android.settingslib.animation.DisappearAnimationUtils;
72 
73 import com.google.android.setupdesign.util.ThemeHelper;
74 
75 import java.util.ArrayList;
76 
77 public class ConfirmLockPassword extends ConfirmDeviceCredentialBaseActivity {
78 
79     // The index of the array is isStrongAuth << 1 + isAlpha.
80     private static final int[] DETAIL_TEXTS = new int[] {
81         R.string.lockpassword_confirm_your_pin_generic,
82         R.string.lockpassword_confirm_your_password_generic,
83         R.string.lockpassword_strong_auth_required_device_pin,
84         R.string.lockpassword_strong_auth_required_device_password,
85     };
86 
87     public static class InternalActivity extends ConfirmLockPassword {
88     }
89 
90 
91     @Override
onCreate(Bundle savedInstanceState)92     protected void onCreate(Bundle savedInstanceState) {
93         super.onCreate(savedInstanceState);
94         if (ThemeHelper.shouldApplyGlifExpressiveStyle(getApplicationContext())) {
95             if (!ThemeHelper.trySetSuwTheme(this)) {
96                 setTheme(ThemeHelper.getSuwDefaultTheme(getApplicationContext()));
97                 ThemeHelper.trySetDynamicColor(this);
98             }
99         }
100     }
101 
102     @Override
getIntent()103     public Intent getIntent() {
104         Intent modIntent = new Intent(super.getIntent());
105         modIntent.putExtra(EXTRA_SHOW_FRAGMENT, ConfirmLockPasswordFragment.class.getName());
106         return modIntent;
107     }
108 
109     @Override
isValidFragment(String fragmentName)110     protected boolean isValidFragment(String fragmentName) {
111         if (ConfirmLockPasswordFragment.class.getName().equals(fragmentName)) return true;
112         return false;
113     }
114 
115     @Override
onWindowFocusChanged(boolean hasFocus)116     public void onWindowFocusChanged(boolean hasFocus) {
117         super.onWindowFocusChanged(hasFocus);
118         Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_content);
119         if (fragment != null && fragment instanceof ConfirmLockPasswordFragment) {
120             ((ConfirmLockPasswordFragment) fragment).onWindowFocusChanged(hasFocus);
121         }
122     }
123 
124     public static class ConfirmLockPasswordFragment extends ConfirmDeviceCredentialBaseFragment
125             implements OnClickListener, OnEditorActionListener,
126             CredentialCheckResultTracker.Listener, SaveAndFinishWorker.Listener,
127             RemoteLockscreenValidationFragment.Listener {
128         private static final String FRAGMENT_TAG_CHECK_LOCK_RESULT = "check_lock_result";
129         private ImeAwareEditText mPasswordEntry;
130         private TextViewInputDisabler mPasswordEntryInputDisabler;
131         private AsyncTask<?, ?, ?> mPendingLockCheck;
132         private CredentialCheckResultTracker mCredentialCheckResultTracker;
133         private boolean mDisappearing = false;
134         private CountDownTimer mCountdownTimer;
135         private boolean mIsAlpha;
136         private InputMethodManager mImm;
137         private AppearAnimationUtils mAppearAnimationUtils;
138         private DisappearAnimationUtils mDisappearAnimationUtils;
139         private boolean mIsManagedProfile;
140         private CharSequence mCheckBoxLabel;
141 
142         // required constructor for fragments
ConfirmLockPasswordFragment()143         public ConfirmLockPasswordFragment() {
144 
145         }
146 
147         @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)148         public View onCreateView(LayoutInflater inflater, ViewGroup container,
149                 Bundle savedInstanceState) {
150             final int storedQuality = mLockPatternUtils.getKeyguardStoredPasswordQuality(
151                     mEffectiveUserId);
152 
153             ConfirmLockPassword activity = (ConfirmLockPassword) getActivity();
154             View view = inflater.inflate(
155                     activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.NORMAL
156                             ? R.layout.confirm_lock_password_normal
157                             : R.layout.confirm_lock_password,
158                     container,
159                     false);
160             mGlifLayout = view.findViewById(R.id.setup_wizard_layout);
161             mPasswordEntry = (ImeAwareEditText) view.findViewById(R.id.password_entry);
162             mPasswordEntry.setOnEditorActionListener(this);
163             // EditText inside ScrollView doesn't automatically get focus.
164             mPasswordEntry.requestFocus();
165             mPasswordEntryInputDisabler = new TextViewInputDisabler(mPasswordEntry);
166             mErrorTextView = (TextView) view.findViewById(R.id.errorText);
167 
168             if (mRemoteValidation) {
169                 mIsAlpha = mRemoteLockscreenValidationSession.getLockType()
170                         == KeyguardManager.PASSWORD;
171                 // ProgressBar visibility is set to GONE until interacted with.
172                 // Set progress bar to INVISIBLE, so the EditText does not get bumped down later.
173                 mGlifLayout.setProgressBarShown(false);
174             } else {
175                 mIsAlpha = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC == storedQuality
176                         || DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC == storedQuality
177                         || DevicePolicyManager.PASSWORD_QUALITY_COMPLEX == storedQuality
178                         || DevicePolicyManager.PASSWORD_QUALITY_MANAGED == storedQuality;
179             }
180             mImm = (InputMethodManager) getActivity().getSystemService(
181                     Context.INPUT_METHOD_SERVICE);
182 
183             mIsManagedProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
184 
185             Intent intent = getActivity().getIntent();
186             if (intent != null) {
187                 CharSequence headerMessage = intent.getCharSequenceExtra(
188                         ConfirmDeviceCredentialBaseFragment.HEADER_TEXT);
189                 CharSequence detailsMessage = intent.getCharSequenceExtra(
190                         ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
191                 if (TextUtils.isEmpty(headerMessage) && mIsManagedProfile) {
192                     headerMessage = mDevicePolicyManager.getOrganizationNameForUser(mUserId);
193                 }
194                 if (TextUtils.isEmpty(headerMessage)) {
195                     headerMessage = getDefaultHeader();
196                 }
197                 if (TextUtils.isEmpty(detailsMessage)) {
198                     detailsMessage = getDefaultDetails();
199                 }
200                 mGlifLayout.setHeaderText(headerMessage);
201 
202                 if (mIsManagedProfile) {
203                     mGlifLayout.getDescriptionTextView().setVisibility(View.GONE);
204                 } else {
205                     mGlifLayout.setDescriptionText(detailsMessage);
206                 }
207                 mCheckBoxLabel = intent.getCharSequenceExtra(KeyguardManager.EXTRA_CHECKBOX_LABEL);
208             }
209             int currentType = mPasswordEntry.getInputType();
210             if (mIsAlpha) {
211                 mPasswordEntry.setInputType(currentType);
212                 mPasswordEntry.setContentDescription(
213                         getContext().getString(R.string.unlock_accessibility_password));
214             } else {
215                 mPasswordEntry.setInputType(
216                         InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
217                 mPasswordEntry.setContentDescription(
218                         getContext().getString(R.string.unlock_accessibility_pin_area));
219             }
220             // Can't set via XML since setInputType resets the fontFamily to null
221             mPasswordEntry.setTypeface(Typeface.create(
222                     getContext().getString(com.android.internal.R.string.config_headlineFontFamily),
223                     Typeface.NORMAL));
224             mAppearAnimationUtils = new AppearAnimationUtils(getContext(),
225                     220, 2f /* translationScale */, 1f /* delayScale*/,
226                     AnimationUtils.loadInterpolator(getContext(),
227                             android.R.interpolator.linear_out_slow_in));
228             mDisappearAnimationUtils = new DisappearAnimationUtils(getContext(),
229                     110, 1f /* translationScale */,
230                     0.5f /* delayScale */, AnimationUtils.loadInterpolator(
231                             getContext(), android.R.interpolator.fast_out_linear_in));
232             setAccessibilityTitle(mGlifLayout.getHeaderText());
233 
234             mCredentialCheckResultTracker = (CredentialCheckResultTracker) getFragmentManager()
235                     .findFragmentByTag(FRAGMENT_TAG_CHECK_LOCK_RESULT);
236             if (mCredentialCheckResultTracker == null) {
237                 mCredentialCheckResultTracker = new CredentialCheckResultTracker();
238                 getFragmentManager().beginTransaction().add(mCredentialCheckResultTracker,
239                         FRAGMENT_TAG_CHECK_LOCK_RESULT).commit();
240             }
241 
242             return view;
243         }
244 
245         @Override
onViewCreated(View view, @Nullable Bundle savedInstanceState)246         public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
247             super.onViewCreated(view, savedInstanceState);
248             if (mRemoteValidation) {
249                 if (mCheckBox != null) {
250                     mCheckBox.setText(TextUtils.isEmpty(mCheckBoxLabel)
251                             ? getDefaultCheckboxLabel()
252                             : mCheckBoxLabel);
253                 }
254                 if (mCancelButton != null && TextUtils.isEmpty(mAlternateButtonText)) {
255                     mCancelButton.setText(mIsAlpha
256                             ? R.string.lockpassword_forgot_password
257                             : R.string.lockpassword_forgot_pin);
258                 }
259                 updateRemoteLockscreenValidationViews();
260             }
261 
262             if (mForgotButton != null) {
263                 mForgotButton.setText(mIsAlpha
264                         ? R.string.lockpassword_forgot_password
265                         : R.string.lockpassword_forgot_pin);
266             }
267         }
268 
269         @Override
onDestroy()270         public void onDestroy() {
271             super.onDestroy();
272             if (mPasswordEntry != null) {
273                 mPasswordEntry.setText(null);
274             }
275             // Force a garbage collection to remove remnant of user password shards from memory.
276             // Execute this with a slight delay to allow the activity lifecycle to complete and
277             // the instance to become gc-able.
278             new Handler(Looper.myLooper()).postDelayed(() -> {
279                 System.gc();
280                 System.runFinalization();
281                 System.gc();
282             }, 5000);
283         }
284 
getDefaultHeader()285         private String getDefaultHeader() {
286             if (mFrp) {
287                 return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_header_frp)
288                         : getString(R.string.lockpassword_confirm_your_pin_header_frp);
289             }
290             if (mRepairMode) {
291                 return mIsAlpha
292                         ? getString(R.string.lockpassword_confirm_repair_mode_password_header)
293                         : getString(R.string.lockpassword_confirm_repair_mode_pin_header);
294             }
295             if (mRemoteValidation) {
296                 return getString(R.string.lockpassword_remote_validation_header);
297             }
298             if (mIsManagedProfile) {
299                 if (mIsAlpha) {
300                     return mDevicePolicyManager.getResources().getString(
301                             CONFIRM_WORK_PROFILE_PASSWORD_HEADER,
302                             () -> getString(
303                                     R.string.lockpassword_confirm_your_work_password_header));
304                 }
305                 return mDevicePolicyManager.getResources().getString(
306                         CONFIRM_WORK_PROFILE_PIN_HEADER,
307                         () -> getString(R.string.lockpassword_confirm_your_work_pin_header));
308             }
309             if (android.multiuser.Flags.showCustomUnlockTitleInsidePrivateProfile()
310                     && Utils.isPrivateProfile(mEffectiveUserId, getActivity())
311                     && !UserManager.get(getActivity())
312                     .isQuietModeEnabled(UserHandle.of(mEffectiveUserId))) {
313                 return mIsAlpha ? getString(R.string.private_space_confirm_your_password_header)
314                         : getString(R.string.private_space_confirm_your_pin_header);
315             }
316 
317             return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_header)
318                     : getString(R.string.lockpassword_confirm_your_pin_header);
319         }
320 
getDefaultDetails()321         private String getDefaultDetails() {
322             if (mFrp) {
323                 return mIsAlpha ? getString(R.string.lockpassword_confirm_your_password_details_frp)
324                         : getString(R.string.lockpassword_confirm_your_pin_details_frp);
325             }
326             if (mRepairMode) {
327                 return mIsAlpha
328                         ? getString(R.string.lockpassword_confirm_repair_mode_password_details)
329                         : getString(R.string.lockpassword_confirm_repair_mode_pin_details);
330             }
331             if (mRemoteValidation) {
332                 return getContext().getString(mIsAlpha
333                         ? R.string.lockpassword_remote_validation_password_details
334                         : R.string.lockpassword_remote_validation_pin_details);
335             }
336             boolean isStrongAuthRequired = isStrongAuthRequired();
337             // Map boolean flags to an index by isStrongAuth << 1 + isAlpha.
338             int index = ((isStrongAuthRequired ? 1 : 0) << 1) + (mIsAlpha ? 1 : 0);
339             return getString(DETAIL_TEXTS[index]);
340         }
341 
getDefaultCheckboxLabel()342         private String getDefaultCheckboxLabel() {
343             if (mRemoteValidation) {
344                 return getString(mIsAlpha
345                         ? R.string.lockpassword_remote_validation_set_password_as_screenlock
346                         : R.string.lockpassword_remote_validation_set_pin_as_screenlock);
347             }
348             throw new IllegalStateException(
349                     "Trying to get default checkbox label for illegal flow");
350         }
351 
getErrorMessage()352         private int getErrorMessage() {
353             return mIsAlpha ? R.string.lockpassword_invalid_password
354                     : R.string.lockpassword_invalid_pin;
355         }
356 
357         @Override
getLastTryOverrideErrorMessageId(int userType)358         protected String getLastTryOverrideErrorMessageId(int userType) {
359             if (userType == USER_TYPE_MANAGED_PROFILE) {
360                 return mIsAlpha ?  WORK_PROFILE_LAST_PASSWORD_ATTEMPT_BEFORE_WIPE
361                         : WORK_PROFILE_LAST_PIN_ATTEMPT_BEFORE_WIPE;
362             }
363 
364             return UNDEFINED;
365         }
366 
367         @Override
getLastTryDefaultErrorMessage(int userType)368         protected int getLastTryDefaultErrorMessage(int userType) {
369             switch (userType) {
370                 case USER_TYPE_PRIMARY:
371                     return mIsAlpha ? R.string.lock_last_password_attempt_before_wipe_device
372                             : R.string.lock_last_pin_attempt_before_wipe_device;
373                 case USER_TYPE_MANAGED_PROFILE:
374                     return mIsAlpha ? R.string.lock_last_password_attempt_before_wipe_profile
375                             : R.string.lock_last_pin_attempt_before_wipe_profile;
376                 case USER_TYPE_SECONDARY:
377                     return mIsAlpha ? R.string.lock_last_password_attempt_before_wipe_user
378                             : R.string.lock_last_pin_attempt_before_wipe_user;
379                 default:
380                     throw new IllegalArgumentException("Unrecognized user type:" + userType);
381             }
382         }
383 
384         @Override
prepareEnterAnimation()385         public void prepareEnterAnimation() {
386             super.prepareEnterAnimation();
387             mGlifLayout.getHeaderTextView().setAlpha(0f);
388             mGlifLayout.getDescriptionTextView().setAlpha(0f);
389             mCancelButton.setAlpha(0f);
390             if (mForgotButton != null) {
391                 mForgotButton.setAlpha(0f);
392             }
393             mPasswordEntry.setAlpha(0f);
394             mErrorTextView.setAlpha(0f);
395         }
396 
getActiveViews()397         private View[] getActiveViews() {
398             ArrayList<View> result = new ArrayList<>();
399             result.add(mGlifLayout.getHeaderTextView());
400             result.add(mGlifLayout.getDescriptionTextView());
401             if (mCancelButton.getVisibility() == View.VISIBLE) {
402                 result.add(mCancelButton);
403             }
404             if (mForgotButton != null) {
405                 result.add(mForgotButton);
406             }
407             result.add(mPasswordEntry);
408             result.add(mErrorTextView);
409             return result.toArray(new View[] {});
410         }
411 
412         @Override
startEnterAnimation()413         public void startEnterAnimation() {
414             super.startEnterAnimation();
415             mAppearAnimationUtils.startAnimation(getActiveViews(), this::updatePasswordEntry);
416         }
417 
418         @Override
onPause()419         public void onPause() {
420             super.onPause();
421             if (mCountdownTimer != null) {
422                 mCountdownTimer.cancel();
423                 mCountdownTimer = null;
424             }
425             mCredentialCheckResultTracker.setListener(null);
426             if (mRemoteLockscreenValidationFragment != null) {
427                 mRemoteLockscreenValidationFragment.setListener(null, /* handler= */ null);
428             }
429         }
430 
431         @Override
getMetricsCategory()432         public int getMetricsCategory() {
433             return SettingsEnums.CONFIRM_LOCK_PASSWORD;
434         }
435 
436         @Override
onResume()437         public void onResume() {
438             super.onResume();
439             long deadline = mLockPatternUtils.getLockoutAttemptDeadline(mEffectiveUserId);
440             if (deadline != 0) {
441                 mCredentialCheckResultTracker.clearResult();
442                 handleAttemptLockout(deadline);
443             } else {
444                 updatePasswordEntry();
445                 mErrorTextView.setText("");
446                 updateErrorMessage(
447                         mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId));
448             }
449             mCredentialCheckResultTracker.setListener(this);
450             if (mRemoteLockscreenValidationFragment != null) {
451                 mRemoteLockscreenValidationFragment.setListener(this, mHandler);
452             }
453         }
454 
455         @Override
authenticationSucceeded()456         protected void authenticationSucceeded() {
457             mCredentialCheckResultTracker.setResult(true, new Intent(), 0, mEffectiveUserId);
458         }
459 
updatePasswordEntry()460         private void updatePasswordEntry() {
461             final boolean isLockedOut =
462                     mLockPatternUtils.getLockoutAttemptDeadline(mEffectiveUserId) != 0;
463             final boolean isRemoteLockscreenValidationInProgress =
464                     mRemoteLockscreenValidationFragment != null
465                     && mRemoteLockscreenValidationFragment.isRemoteValidationInProgress();
466             boolean shouldEnableInput = !isLockedOut && !isRemoteLockscreenValidationInProgress;
467             mPasswordEntry.setEnabled(shouldEnableInput);
468             mPasswordEntryInputDisabler.setInputEnabled(shouldEnableInput);
469             if (shouldEnableInput) {
470                 mPasswordEntry.scheduleShowSoftInput();
471                 mPasswordEntry.requestFocus();
472             } else {
473                 mImm.hideSoftInputFromWindow(mPasswordEntry.getWindowToken(), /* flags= */0);
474             }
475         }
476 
onWindowFocusChanged(boolean hasFocus)477         public void onWindowFocusChanged(boolean hasFocus) {
478             if (!hasFocus) {
479                 return;
480             }
481             // Post to let window focus logic to finish to allow soft input show/hide properly.
482             mPasswordEntry.post(this::updatePasswordEntry);
483         }
484 
handleNext()485         private void handleNext() {
486             if (mPendingLockCheck != null || mDisappearing) {
487                 return;
488             }
489 
490             // TODO(b/120484642): This is a point of entry for passwords from the UI
491             final Editable passwordText = mPasswordEntry.getText();
492             if (TextUtils.isEmpty(passwordText)) {
493                 return;
494             }
495             final LockscreenCredential credential = mIsAlpha
496                     ? LockscreenCredential.createPassword(passwordText)
497                     : LockscreenCredential.createPin(passwordText);
498 
499             mPasswordEntryInputDisabler.setInputEnabled(false);
500 
501             if (mRemoteValidation) {
502                 validateGuess(credential);
503                 updateRemoteLockscreenValidationViews();
504                 updatePasswordEntry();
505                 return;
506             }
507 
508             Intent intent = new Intent();
509             // TODO(b/161956762): Sanitize this
510             if (mReturnGatekeeperPassword) {
511                 if (isInternalActivity()) {
512                     startVerifyPassword(credential, intent,
513                             LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE);
514                     return;
515                 }
516             } else if (mForceVerifyPath)  {
517                 if (isInternalActivity()) {
518                     final int flags = mRequestWriteRepairModePassword
519                             ? LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW : 0;
520                     startVerifyPassword(credential, intent, flags);
521                     return;
522                 }
523             } else {
524                 startCheckPassword(credential, intent);
525                 return;
526             }
527 
528             mCredentialCheckResultTracker.setResult(false, intent, 0, mEffectiveUserId);
529         }
530 
isInternalActivity()531         private boolean isInternalActivity() {
532             return getActivity() instanceof ConfirmLockPassword.InternalActivity;
533         }
534 
startVerifyPassword(LockscreenCredential credential, final Intent intent, @LockPatternUtils.VerifyFlag int flags)535         private void startVerifyPassword(LockscreenCredential credential, final Intent intent,
536                 @LockPatternUtils.VerifyFlag int flags) {
537             final int localEffectiveUserId = mEffectiveUserId;
538             final int localUserId = mUserId;
539             final LockPatternChecker.OnVerifyCallback onVerifyCallback = (response, timeoutMs) -> {
540                 mPendingLockCheck = null;
541                 final boolean matched = response.isMatched();
542                 if (matched && mReturnCredentials) {
543                     if ((flags & LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE) != 0) {
544                         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE,
545                                 response.getGatekeeperPasswordHandle());
546                     } else {
547                         intent.putExtra(
548                                 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN,
549                                 response.getGatekeeperHAT());
550                     }
551                 }
552                 mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
553                         localEffectiveUserId);
554             };
555             mPendingLockCheck = (localEffectiveUserId == localUserId)
556                     ? LockPatternChecker.verifyCredential(mLockPatternUtils, credential,
557                             localUserId, flags, onVerifyCallback)
558                     : LockPatternChecker.verifyTiedProfileChallenge(mLockPatternUtils, credential,
559                             localUserId, flags, onVerifyCallback);
560         }
561 
startCheckPassword(final LockscreenCredential credential, final Intent intent)562         private void startCheckPassword(final LockscreenCredential credential,
563                 final Intent intent) {
564             final int localEffectiveUserId = mEffectiveUserId;
565             mPendingLockCheck = LockPatternChecker.checkCredential(
566                     mLockPatternUtils,
567                     credential,
568                     localEffectiveUserId,
569                     new LockPatternChecker.OnCheckCallback() {
570                         @Override
571                         public void onChecked(boolean matched, int timeoutMs) {
572                             mPendingLockCheck = null;
573                             if (matched && isInternalActivity() && mReturnCredentials) {
574                                 intent.putExtra(
575                                         ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, credential);
576                             }
577                             mCredentialCheckResultTracker.setResult(matched, intent, timeoutMs,
578                                     localEffectiveUserId);
579                         }
580                     });
581         }
582 
startDisappearAnimation(final Intent intent)583         private void startDisappearAnimation(final Intent intent) {
584             ConfirmDeviceCredentialUtils.hideImeImmediately(
585                     getActivity().getWindow().getDecorView());
586 
587             if (mDisappearing) {
588                 return;
589             }
590             mDisappearing = true;
591 
592             final ConfirmLockPassword activity = (ConfirmLockPassword) getActivity();
593             // Bail if there is no active activity.
594             if (activity == null || activity.isFinishing()) {
595                 return;
596             }
597             if (activity.getConfirmCredentialTheme() == ConfirmCredentialTheme.DARK) {
598                 mDisappearAnimationUtils.startAnimation(getActiveViews(), () -> {
599                     activity.setResult(RESULT_OK, intent);
600                     activity.finish();
601                     activity.overridePendingTransition(
602                             R.anim.confirm_credential_close_enter,
603                             R.anim.confirm_credential_close_exit);
604                 });
605             } else {
606                 activity.setResult(RESULT_OK, intent);
607                 activity.finish();
608             }
609         }
610 
onPasswordChecked(boolean matched, Intent intent, int timeoutMs, int effectiveUserId, boolean newResult)611         private void onPasswordChecked(boolean matched, Intent intent, int timeoutMs,
612                 int effectiveUserId, boolean newResult) {
613             mPasswordEntryInputDisabler.setInputEnabled(true);
614             if (matched) {
615                 if (newResult) {
616                     ConfirmDeviceCredentialUtils.reportSuccessfulAttempt(mLockPatternUtils,
617                             mUserManager, mDevicePolicyManager, mEffectiveUserId,
618                             /* isStrongAuth */ true);
619                 }
620                 startDisappearAnimation(intent);
621                 ConfirmDeviceCredentialUtils.checkForPendingIntent(getActivity());
622             } else {
623                 if (timeoutMs > 0) {
624                     refreshLockScreen();
625                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
626                             effectiveUserId, timeoutMs);
627                     handleAttemptLockout(deadline);
628                 } else {
629                     showError(getErrorMessage(), CLEAR_WRONG_ATTEMPT_TIMEOUT_MS);
630                 }
631                 if (newResult) {
632                     reportFailedAttempt();
633                 }
634             }
635         }
636 
637         @Override
onRemoteLockscreenValidationResult( RemoteLockscreenValidationResult result)638         public void onRemoteLockscreenValidationResult(
639                 RemoteLockscreenValidationResult result) {
640             switch (result.getResultCode()) {
641                 case RemoteLockscreenValidationResult.RESULT_GUESS_VALID:
642                     if (mCheckBox.isChecked() && mRemoteLockscreenValidationFragment
643                             .getLockscreenCredential() != null) {
644                         Log.i(TAG, "Setting device screen lock to the other device's screen lock.");
645                         SaveAndFinishWorker saveAndFinishWorker = new SaveAndFinishWorker();
646                         getFragmentManager().beginTransaction().add(saveAndFinishWorker, null)
647                                 .commit();
648                         getFragmentManager().executePendingTransactions();
649                         saveAndFinishWorker
650                                 .setListener(this)
651                                 .setRequestGatekeeperPasswordHandle(true);
652                         saveAndFinishWorker.start(
653                                 mLockPatternUtils,
654                                 mRemoteLockscreenValidationFragment.getLockscreenCredential(),
655                                 /* currentCredential= */ null,
656                                 mEffectiveUserId);
657                     } else {
658                         mCredentialCheckResultTracker.setResult(/* matched= */ true, new Intent(),
659                                 /* timeoutMs= */ 0, mEffectiveUserId);
660                     }
661                     return;
662                 case RemoteLockscreenValidationResult.RESULT_GUESS_INVALID:
663                     mCredentialCheckResultTracker.setResult(/* matched= */ false, new Intent(),
664                             /* timeoutMs= */ 0, mEffectiveUserId);
665                     break;
666                 case RemoteLockscreenValidationResult.RESULT_LOCKOUT:
667                     mCredentialCheckResultTracker.setResult(/* matched= */ false, new Intent(),
668                             (int) result.getTimeoutMillis(), mEffectiveUserId);
669                     break;
670                 case RemoteLockscreenValidationResult.RESULT_NO_REMAINING_ATTEMPTS:
671                 case RemoteLockscreenValidationResult.RESULT_SESSION_EXPIRED:
672                     onRemoteLockscreenValidationFailure(String.format(
673                             "Cannot continue remote lockscreen validation. ResultCode=%d",
674                             result.getResultCode()));
675                     break;
676             }
677             updateRemoteLockscreenValidationViews();
678             updatePasswordEntry();
679             mRemoteLockscreenValidationFragment.clearLockscreenCredential();
680         }
681 
682         @Override
onCredentialChecked(boolean matched, Intent intent, int timeoutMs, int effectiveUserId, boolean newResult)683         public void onCredentialChecked(boolean matched, Intent intent, int timeoutMs,
684                 int effectiveUserId, boolean newResult) {
685             onPasswordChecked(matched, intent, timeoutMs, effectiveUserId, newResult);
686         }
687 
688         @Override
onShowError()689         protected void onShowError() {
690             mPasswordEntry.setText(null);
691         }
692 
handleAttemptLockout(long elapsedRealtimeDeadline)693         private void handleAttemptLockout(long elapsedRealtimeDeadline) {
694             clearResetErrorRunnable();
695             mCountdownTimer = new CountDownTimer(
696                     elapsedRealtimeDeadline - SystemClock.elapsedRealtime(),
697                     LockPatternUtils.FAILED_ATTEMPT_COUNTDOWN_INTERVAL_MS) {
698 
699                 @Override
700                 public void onTick(long millisUntilFinished) {
701                     final int secondsCountdown = (int) (millisUntilFinished / 1000);
702                     showError(getString(
703                             R.string.lockpattern_too_many_failed_confirmation_attempts,
704                             secondsCountdown), 0);
705                 }
706 
707                 @Override
708                 public void onFinish() {
709                     updatePasswordEntry();
710                     mErrorTextView.setText("");
711                     updateErrorMessage(
712                             mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId));
713                 }
714             }.start();
715             updatePasswordEntry();
716         }
717 
onClick(View v)718         public void onClick(View v) {
719             if (v.getId() == R.id.next_button) {
720                 handleNext();
721             } else if (v.getId() == R.id.cancel_button) {
722                 getActivity().setResult(RESULT_CANCELED);
723                 getActivity().finish();
724             }
725         }
726 
727         // {@link OnEditorActionListener} methods.
onEditorAction(TextView v, int actionId, KeyEvent event)728         public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
729             // Check if this was the result of hitting the enter or "done" key
730             if (actionId == EditorInfo.IME_NULL
731                     || actionId == EditorInfo.IME_ACTION_DONE
732                     || actionId == EditorInfo.IME_ACTION_NEXT) {
733                 handleNext();
734                 return true;
735             }
736             return false;
737         }
738 
739         /**
740          * Callback for when the current device's lockscreen was set to the guess used for
741          * remote lockscreen validation.
742          */
743         @Override
onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData)744         public void onChosenLockSaveFinished(boolean wasSecureBefore, Intent resultData) {
745             Log.i(TAG, "Device lockscreen has been set to remote device's lockscreen.");
746             mRemoteLockscreenValidationFragment.clearLockscreenCredential();
747 
748             Intent result = new Intent();
749             if (mRemoteValidation && containsGatekeeperPasswordHandle(resultData)) {
750                 result.putExtra(EXTRA_KEY_GK_PW_HANDLE, getGatekeeperPasswordHandle(resultData));
751                 SetupRedactionInterstitial.setEnabled(getContext(), true);
752             }
753             mCredentialCheckResultTracker.setResult(/* matched= */ true, result,
754                     /* timeoutMs= */ 0, mEffectiveUserId);
755         }
756     }
757 }
758