1 /* 2 * Copyright (C) 2018 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.car.settings.security; 18 19 import android.content.Context; 20 import android.os.Bundle; 21 import android.os.UserHandle; 22 import android.view.View; 23 import android.widget.TextView; 24 25 import androidx.annotation.LayoutRes; 26 import androidx.annotation.StringRes; 27 28 import com.android.car.settings.R; 29 import com.android.car.settings.common.BaseFragment; 30 import com.android.internal.widget.LockPatternUtils; 31 import com.android.internal.widget.LockPatternView; 32 import com.android.internal.widget.LockscreenCredential; 33 34 import java.util.List; 35 36 /** 37 * Fragment for confirming existing lock pattern 38 */ 39 public class ConfirmLockPatternFragment extends BaseFragment { 40 41 private static final String FRAGMENT_TAG_CHECK_LOCK_WORKER = "check_lock_worker"; 42 // Time we wait before clearing a wrong pattern and the error message. 43 private static final long CLEAR_WRONG_ATTEMPT_TIMEOUT_MS = 2500L; 44 45 private LockPatternView mLockPatternView; 46 private TextView mMsgView; 47 48 private LockPatternUtils mLockPatternUtils; 49 private CheckLockWorker mCheckLockWorker; 50 private CheckLockListener mCheckLockListener; 51 52 private int mUserId; 53 private List<LockPatternView.Cell> mPattern; 54 55 @Override 56 @LayoutRes getLayoutId()57 protected int getLayoutId() { 58 return R.layout.confirm_lock_pattern; 59 } 60 61 @Override 62 @StringRes getTitleId()63 protected int getTitleId() { 64 return R.string.security_settings_title; 65 } 66 67 @Override onAttach(Context context)68 public void onAttach(Context context) { 69 super.onAttach(context); 70 if ((getActivity() instanceof CheckLockListener)) { 71 mCheckLockListener = (CheckLockListener) getActivity(); 72 } else { 73 throw new RuntimeException("The activity must implement CheckLockListener"); 74 } 75 } 76 77 @Override onCreate(Bundle savedInstanceState)78 public void onCreate(Bundle savedInstanceState) { 79 super.onCreate(savedInstanceState); 80 mLockPatternUtils = new LockPatternUtils(getContext()); 81 mUserId = UserHandle.myUserId(); 82 } 83 84 @Override onViewCreated(View view, Bundle savedInstanceState)85 public void onViewCreated(View view, Bundle savedInstanceState) { 86 super.onViewCreated(view, savedInstanceState); 87 88 mMsgView = (TextView) view.findViewById(R.id.message); 89 mLockPatternView = (LockPatternView) view.findViewById(R.id.lockPattern); 90 mLockPatternView.setFadePattern(false); 91 mLockPatternView.setInStealthMode(!mLockPatternUtils.isVisiblePatternEnabled(mUserId)); 92 mLockPatternView.setOnPatternListener(mLockPatternListener); 93 94 if (savedInstanceState != null) { 95 mCheckLockWorker = (CheckLockWorker) getFragmentManager().findFragmentByTag( 96 FRAGMENT_TAG_CHECK_LOCK_WORKER); 97 } 98 } 99 100 @Override onStart()101 public void onStart() { 102 super.onStart(); 103 if (mCheckLockWorker != null) { 104 mCheckLockWorker.setListener(this::onCheckCompleted); 105 } 106 } 107 108 @Override onStop()109 public void onStop() { 110 super.onStop(); 111 if (mCheckLockWorker != null) { 112 mCheckLockWorker.setListener(null); 113 } 114 } 115 116 private Runnable mClearErrorRunnable = () -> { 117 mLockPatternView.clearPattern(); 118 mMsgView.setText(""); 119 }; 120 121 private LockPatternView.OnPatternListener mLockPatternListener = 122 new LockPatternView.OnPatternListener() { 123 124 public void onPatternStart() { 125 mLockPatternView.removeCallbacks(mClearErrorRunnable); 126 mMsgView.setText(""); 127 } 128 129 public void onPatternCleared() { 130 mLockPatternView.removeCallbacks(mClearErrorRunnable); 131 } 132 133 public void onPatternCellAdded(List<LockPatternView.Cell> pattern) { 134 } 135 136 public void onPatternDetected(List<LockPatternView.Cell> pattern) { 137 mLockPatternView.setEnabled(false); 138 139 if (mCheckLockWorker == null) { 140 mCheckLockWorker = new CheckLockWorker(); 141 mCheckLockWorker.setListener( 142 ConfirmLockPatternFragment.this::onCheckCompleted); 143 144 getFragmentManager() 145 .beginTransaction() 146 .add(mCheckLockWorker, FRAGMENT_TAG_CHECK_LOCK_WORKER) 147 .commitNow(); 148 } 149 150 mPattern = pattern; 151 mCheckLockWorker.checkPattern(mUserId, pattern); 152 } 153 }; 154 onCheckCompleted(boolean lockMatched)155 private void onCheckCompleted(boolean lockMatched) { 156 if (lockMatched) { 157 mCheckLockListener.onLockVerified(LockscreenCredential.createPattern(mPattern)); 158 } else { 159 mLockPatternView.setEnabled(true); 160 mMsgView.setText(R.string.lockpattern_pattern_wrong); 161 162 // Set timer to clear wrong pattern 163 mLockPatternView.removeCallbacks(mClearErrorRunnable); 164 mLockPatternView.postDelayed(mClearErrorRunnable, CLEAR_WRONG_ATTEMPT_TIMEOUT_MS); 165 } 166 } 167 } 168