| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.car.settings.security; |
| |
| import android.content.Context; |
| import android.os.Bundle; |
| import android.os.UserHandle; |
| import android.view.View; |
| import android.widget.TextView; |
| |
| import androidx.annotation.LayoutRes; |
| import androidx.annotation.StringRes; |
| |
| import com.android.car.settings.R; |
| import com.android.car.settings.common.BaseFragment; |
| import com.android.internal.widget.LockPatternView; |
| import com.android.internal.widget.LockscreenCredential; |
| |
| import java.util.List; |
| |
| /** |
| * Fragment for confirming existing lock pattern |
| */ |
| public class ConfirmLockPatternFragment extends BaseFragment { |
| |
| private static final String FRAGMENT_TAG_CHECK_LOCK_WORKER = "check_lock_worker"; |
| // Time we wait before clearing a wrong pattern and the error message. |
| private static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 2500L; |
| |
| private LockPatternView mLockPatternView; |
| private TextView mMsgView; |
| |
| private CheckLockWorker mCheckLockWorker; |
| private CheckLockListener mCheckLockListener; |
| |
| private int mUserId; |
| private List<LockPatternView.Cell> mPattern; |
| |
| private ConfirmLockLockoutHelper mConfirmLockLockoutHelper; |
| |
| @Override |
| @LayoutRes |
| protected int getLayoutId() { |
| return R.layout.confirm_lock_pattern; |
| } |
| |
| @Override |
| @StringRes |
| protected int getTitleId() { |
| return R.string.security_settings_title; |
| } |
| |
| @Override |
| public void onAttach(Context context) { |
| super.onAttach(context); |
| if ((getActivity() instanceof CheckLockListener)) { |
| mCheckLockListener = (CheckLockListener) getActivity(); |
| } else { |
| throw new RuntimeException("The activity must implement CheckLockListener"); |
| } |
| |
| mUserId = UserHandle.myUserId(); |
| mConfirmLockLockoutHelper = ConfirmLockLockoutHelper.getInstance(requireContext(), mUserId); |
| } |
| |
| @Override |
| public void onViewCreated(View view, Bundle savedInstanceState) { |
| super.onViewCreated(view, savedInstanceState); |
| |
| mMsgView = (TextView) view.findViewById(R.id.message); |
| mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern); |
| mLockPatternView.setFadePattern(false); |
| mLockPatternView.setInStealthMode( |
| !mConfirmLockLockoutHelper.getLockPatternUtils().isVisiblePatternEnabled(mUserId)); |
| mLockPatternView.setOnPatternListener(mLockPatternListener); |
| mConfirmLockLockoutHelper.setConfirmLockUIController( |
| new ConfirmLockLockoutHelper.ConfirmLockUIController() { |
| @Override |
| public void setErrorText(String text) { |
| mMsgView.setText(text); |
| } |
| |
| @Override |
| public void refreshUI(boolean isLockedOut) { |
| mLockPatternView.setEnabled(!isLockedOut); |
| mLockPatternView.clearPattern(); |
| } |
| }); |
| |
| if (savedInstanceState != null) { |
| mCheckLockWorker = (CheckLockWorker) getFragmentManager().findFragmentByTag( |
| FRAGMENT_TAG_CHECK_LOCK_WORKER); |
| } |
| } |
| |
| @Override |
| public void onStart() { |
| super.onStart(); |
| if (mCheckLockWorker != null) { |
| mCheckLockWorker.setListener(this::onCheckCompleted); |
| } |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| |
| mConfirmLockLockoutHelper.onResumeUI(); |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| |
| mConfirmLockLockoutHelper.onPauseUI(); |
| } |
| |
| @Override |
| public void onStop() { |
| super.onStop(); |
| if (mCheckLockWorker != null) { |
| mCheckLockWorker.setListener(null); |
| } |
| } |
| |
| private Runnable mClearErrorRunnable = () -> { |
| mLockPatternView.setEnabled(true); |
| mLockPatternView.clearPattern(); |
| mMsgView.setText(""); |
| }; |
| |
| private LockPatternView.OnPatternListener mLockPatternListener = |
| new LockPatternView.OnPatternListener() { |
| |
| public void onPatternStart() { |
| mLockPatternView.removeCallbacks(mClearErrorRunnable); |
| mMsgView.setText(""); |
| } |
| |
| public void onPatternCleared() { |
| mLockPatternView.removeCallbacks(mClearErrorRunnable); |
| } |
| |
| public void onPatternCellAdded(List<LockPatternView.Cell> pattern) { |
| } |
| |
| public void onPatternDetected(List<LockPatternView.Cell> pattern) { |
| mLockPatternView.setEnabled(false); |
| |
| if (mCheckLockWorker == null) { |
| mCheckLockWorker = new CheckLockWorker(); |
| mCheckLockWorker.setListener( |
| ConfirmLockPatternFragment.this::onCheckCompleted); |
| |
| getFragmentManager() |
| .beginTransaction() |
| .add(mCheckLockWorker, FRAGMENT_TAG_CHECK_LOCK_WORKER) |
| .commitNow(); |
| } |
| |
| mPattern = pattern; |
| mCheckLockWorker.checkPattern(mUserId, pattern); |
| } |
| }; |
| |
| private void onCheckCompleted(boolean lockMatched, int timeoutMs) { |
| if (lockMatched) { |
| try (LockscreenCredential patternCred = LockscreenCredential.createPattern(mPattern)) { |
| // onLockVerified does not take ownership of the LockscreenCredential |
| // see CheckLockActivity#onLockVerified and VerifyLockChangeActivity#onLockVerified |
| mCheckLockListener.onLockVerified(patternCred); |
| } |
| } else { |
| if (timeoutMs > 0) { |
| mConfirmLockLockoutHelper.onCheckCompletedWithTimeout(timeoutMs); |
| } else { |
| mLockPatternView.setEnabled(true); |
| mMsgView.setText(R.string.lockpattern_pattern_wrong); |
| |
| // Set timer to clear wrong pattern |
| mLockPatternView.removeCallbacks(mClearErrorRunnable); |
| mLockPatternView.postDelayed(mClearErrorRunnable, CLEAR_WRONG_ATTEMPT_TIMEOUT_MS); |
| } |
| } |
| } |
| } |